## NewGRF Town Feature Additions to NewGRF Specifications in JGR's Patchpack in NML

This document describes the non-standard additions to the town feature in the Official OpenTTD NML Specifications, as implemented in this patchpack, and the associated NML fork

This feature allows directly referencing the town feature.
Ordinarily this is only accessible as the parent scope for the features: stations, bridges, houses, industries, objects, road stops.

This feature may not necessarily match implementations in other patches, branches, etc.
This feature as implemented here MAY also be present in other patchpacks.

The feature identifier is FEAT_TOWN.

See the NewGRF additions (NML) document for background information on additions to NML.

See the associated non-NML document for more details on the additions to the NewGRF town feature.

This feature will be automatically skipped when loaded into a version of OpenTTD which does not support this feature.
If this feature is the only significant thing in this GRF, the extended_feature_test(...) function SHOULD be called with the specific feature(s) used and some message, error or other form of signalling to the user used to inform the user that this version of OpenTTD does not support the feature, if the return value is false.
Otherwise the GRF could silently do nothing instead of the expected functionality, creating confusion for end users.

Sections:

- Variables
- Generic Callbacks
- Syntax example

### Additional Town Variables

See NML town variables for context.

Name | Value range | Comment | Requires feature
--- | --- | --- | ---
num_houses_uncapped | 0..4294967295 | Number of town houses (not clamped to 0xFFFF) | town_uncapped_variables, version 1
population_uncapped | 0..4294967295 | Town population (not clamped to 0xFFFF) | town_uncapped_variables, version 1
town_zone_0_radius_square_uncapped | 0..4294967295 | Town zone 0 radius squared (not clamped to 0xFFFF) | town_uncapped_variables, version 1
town_zone_1_radius_square_uncapped | 0..4294967295 | Town zone 1 radius squared (not clamped to 0xFFFF) | town_uncapped_variables, version 1
town_zone_2_radius_square_uncapped | 0..4294967295 | Town zone 2 radius squared (not clamped to 0xFFFF) | town_uncapped_variables, version 1
town_zone_3_radius_square_uncapped | 0..4294967295 | Town zone 3 radius squared (not clamped to 0xFFFF) | town_uncapped_variables, version 1
town_zone_4_radius_square_uncapped | 0..4294967295 | Town zone 4 radius squared (not clamped to 0xFFFF) | town_uncapped_variables, version 1
x_coordinate | 0..65535 | X coordinate of town tile | varaction2_towns_town_xy, version 1
y_coordinate | 0..65535 | Y coordinate of town tile | varaction2_towns_town_xy, version 1

### Town Generic Callbacks

Currently only the town_zone callback is defined.
This requires the feature: town_zone_callback, version 1.

    	item (FEAT_TOWN, ..., GENERIC_CALLBACK) {
    		graphics {
    			town_zone: ...;
    		}
    	}

This callback is called whenever the zone radii of a town need to be recalculated.
This can occur when:

- The number of houses in the town changes
- When the game is loaded
- When settings, NewGRFs or other relevant game configuration is changed

The callback is not called if the town zone radii calculations have been manually overriden by settings.

The return value of the callback is the version of the result format returned by the callback.
Currently only version 0 is defined.
The callback must store the values of the town zone radii into registers: 0x100 to 0x104, for zones 0 to 4 respectively, using STORE_TEMP.

A callback failure result should be returned to use the default town zone radii calculation (or to allow another GRF to handle the callback).

The num_houses_uncapped variable should be used instead of num_houses, otherwise the results may be incorrect for large towns.
Implementers of this callback may assume that the town_uncapped_variables feature is present.

### Syntax example

    grf {
    	...
    }

    if (!extended_feature_test("town_zone_callback")) {
    	error(FATAL, string(STR_UNSUPPORTED_VERSION));
    }

    switch (FEAT_TOWN, SELF, town_zone_cb,
    		[
    			STORE_TEMP(num_houses_uncapped * (is_city ? 32 : 16), 0x100),
    			STORE_TEMP((num_houses_uncapped >> 3) * 9, 0x101),
    			STORE_TEMP(0, 0x102),
    			STORE_TEMP((num_houses_uncapped >> 3) * 5, 0x103),
    			STORE_TEMP((num_houses_uncapped >> 3) * 3, 0x104)
    		]) {
    	return 0;
    }

    item (FEAT_TOWN, town_cb, GENERIC_CALLBACK) {
    	graphics {
    		town_zone: town_zone_cb;
    	}
    }