LuaAPI/wesnoth/map

From The Battle for Wesnoth Wiki
< LuaAPI‎ | wesnoth
Revision as of 17:20, 14 June 2024 by Celtic Minstrel (talk | contribs) (wesnoth.map.iter_adjacent: typo)

(Version 1.15.11 and later only)

This module contains functions for working with the game map. Some of the functions can be called as methods of the map itself. In 1.15.11, there exists only one map in the game context, which can be accessed as wesnoth.current.map, while in the map generation context, a map can be created with #wesnoth.map.create or #wesnoth.map.generate. In future, it may become possible to create maps on the fly or read them from disk.

Functions

wesnoth.map.find

  • wesnoth.map.find(filter config) → list of hex references
  • wesnoth.map.find(filter config, [reference_unit]) → list of hex references
  • wesnoth.map.find(map, filter userdata, [list of locations]) → list of locations
  • wesnoth.map.find_in_radius(map, center, radius, filter userdata) → list of locations

Returns a table containing all the locations matching the given filter. Locations are stored as a hex reference which has x and y keys along with a variety of other functions. See StandardLocationFilter for details about location filters. If a unit is passed, it can be referenced from the filter via the $teleport_unit variable, as well as in WFL formulas used in the filter.

Note: In older versions of Wesnoth, locations returned from a filter were stored as simple pairs, {x,y}. For compatibility purposes, accessing a location this way (as loc[1] and loc[2]) is still supported.

-- replace all grass terrains by roads
for i,loc in ipairs(wesnoth.map.find{terrain = "Gg"}) do
    wesnoth.current.map[loc] = "Rr"
end

The mapgen form of this function uses a different format for the filter which is somewhat experimental. An example of its use:

local map = wesnoth.map.create(18,18,"Gg")

-- Assume there is some generation code here, so the map is no longer just grass

local F, f = wesnoth.map.filter, wesnoth.map.filter_tags

-- Find all elvish villages
local elf_villages = map:find(F(f.terrain('*^Ve')))

-- Find all great trees within 7 tiles of an elvish keep
local elf_keeps = map:find(F(f.terrain('Kv')))
local nearby_trees = map:find_in_radius(elf_keeps, 7, F(f.terrain('*^Fet')))

Possible filter tags for this function are: terrain, all, any, none, notall, adjacent, find_in, radius, x, y, is_loc, formula.

wesnoth.map.get

  • wesnoth.map.get(location) → hex reference

Constructs a hex reference for the specified location.

wesnoth.map.matches

  • wesnoth.map.matches(location, filter config, [reference_unit]) → boolean
  • hex:matches(filter config, [reference_unit]) → boolean
  • map:matches(location, filter userdata) → boolean

Returns true if the given location passes the filter. The location can be passed either as two separate x and y parameters or as an object with x and y keys (such as a hex reference or a unit). If a reference_unit is passed, it can be referenced from the filter via the $teleport_unit variable, as well as in WFL formulas used in the filter.

local b = wesnoth.map.matches(x, y, {
    terrain = "Ww",
    wml.tag.filter_adjacent_location{terrain = "Ds,*^Bw*"}
})

wesnoth.map.on_board

  • wesnoth.map.on_board(map, location, [include border?]) → boolean
  • map:on_board(location, [include border?]) → boolean

Tests if the specified location is on the map. The final parameter determines whether to count the inaccessible map border tiles as being on the map. It defaults to false.

wesnoth.map.on_border

  • wesnoth.map.on_border(map, location) → boolean
  • map:on_border(location) → boolean

Tests if the specified location is on the map's border.

wesnoth.map.iter

  • wesnoth.map.iter(map, [include border?]) → iteratorx, y, terrain code
  • map:iter([include border?) → iteratorx, y, terrain code

Iterate over the entire map, possibly excluding the border tiles. For example:

for x, y in wesnoth.current.map:iter() do
    wesnoth.map.add_label{x=x, y=y, text=string.format("%d,%d", x, y)}
end

wesnoth.map.iter_adjacent

  • wesnoth.map.iter_adjacent(map, location, [include border?]) → iteratorx, y
  • map:iter_adjacent(location, [include border?]) → iteratorx, y

Iterate over the hexes adjacent to the location, excluding border tiles (unless explicitly enabled).

wesnoth.map.read_location

  • wesnoth.read_location(...) → location or nil, number of arguments processed

Extracts a location from the front of a variadic parameter list. The purpose of this is to make it easy for custom user-defined functions to handle locations in the same way as the built-in API functions do. It returns the location (if it was able to find one) and the number of arguments processed, which can be:

  • 0 if nothing resembling a location was found.
  • 1 if a location-like object was found. A location-like object can be either an array of two integers or an object that has numeric x and y keys. Note that a unit userdata satisfies the second criteria, so if a unit is found, its location will be returned.
  • 2 if the first two arguments in the list were integers. In this case, they will be taken as the x and y coordinates.

Usage example

Imagine a function foo with the following signature:

  • foo(bar : string, [home : location], mode : string, [target : location], moo : boolean) → boolean

Using read_location it could be implemented as follows:

function foo(...)
	-- First argument goes in bar
	local bar = ...
	-- Read location starting at the second argument
	local home, n = wesnoth.map.read_location(select(2, ...))
	-- note: n will be 0 if a location wasn't found at that position
	-- This could be an error, or it could be handled as an optional parameter
	-- Next argument after that goes in mode
	local mode = select(n + 2, ...)
	-- Then read a location into target
	local target, m = wesnoth.map.read_location(select(n + 2, ...))
	-- Finally, read a parameter into moo
	local moo = select(m + n + 2, ...)
	-- Do stuff with all these parameters
	return true
end

With that code, all the following invocations of foo work:

foo('a', 'b', true) -- both optional locations omitted
foo('a', 1, 2, 'q', 5, 6, false) -- locations given as separate integer parameters
foo('a', 'm', {1, 7},  true) -- first location omitted, second given as 2-element array
foo('a', some_unit, 'z', {x = 5, y = 10}, false) -- a unit also functions as a location
foo('a', 7, 12, 'q', my_leader, true) -- mixing different forms also works

wesnoth.map.split_terrain_code

  • wesnoth.map.split_terrain_code(code) → base, overlay

Splits a terrain code into a base and an overlay. If the terrain code did not contain a ^, then the overlay will be nil. The returned overlay or base can be an empty string if the code begins or ends with a ^, respectively. Splitting the string '^' will result in two empty strings.

wesnoth.map.make_bitmap

  • wesnoth.map.make_bitmap(array of locations) → shroud data bitmap

Constructs a shroud data string such that the locations in the array are unshrouded and all other locations are shrouded. The string will be the minimum size required to fit all the locations.

wesnoth.map.parse_bitmap

  • wesnoth.map.parse_bitmap(shroud data bitmap) → array of locations

Parses a shroud data string and returns a list of the locations that are unshrouded.

wesnoth.map.terrain_mask

  • wesnoth.map.terrain_mask(map, pivot, mask, [options])
  • map:terrain_mask(pivot, mask, [options])

Overlays a terrain mask on the map. Possible options:

  • is_odd - if true, then the mask is interpreted as if it was cut out from an odd map location.
  • ignore_special_locations - if true, then special locations on the mask won't be added to the map.
  • rules - an array of rules. See TerrainMaskWML for the rule format. This is an array of tables, each of which has the content of a [rule] tag.

wesnoth.map.add_label

  • wesnoth.map.add_label(options)

Adds a label to the map. Takes the same options as the [label] WML tag.

wesnoth.map.remove_label

  • wesnoth.map.remove_label(location)

Removes a label from the map. Normally this removes a global label, but you can also remove team labels with an extra team_name parameter, for example:

-- Removes the label on (3,12) owned by team 'rebels'
wesnoth.map.remove_label{x = 3, y = 12, team_name = 'rebels'}

wesnoth.map.get_label

  • wesnoth.map.get_label(location, [side or team_name]) → label info

Get the full label info for a label on the specified location. With one argument, it returns a global label; otherwise, it returns a label belonging to the specified team. Passing a side (either a side number or a side userdata) uses that side's team. The returned table contains all the possible options that can be passed to add_label.

wesnoth.map.place_area

  • wesnoth.map.place_area(filter)

Add a new named area to the map. The filter is a StandardLocationFilter, but it can also contain an id key and [time] tags. In order to remove the area later, an id must be provided. An area with no [time] tags does not affect the schedule.

wesnoth.map.remove_area

  • wesnoth.map.remove_area(id)

Remove the area with the given ID.

wesnoth.map.get_area

  • wesnoth.map.get_area(id or location) → area schedule

Get the named area with the specified ID, or the area that is active on the specified location (if any). This will return nil if no area is found in either case.

The returned object is a userdata object similar to wesnoth.current.schedule, with the following differences:

  • schedule.liminal_bonus → nil

This key is not supported on area schedules.

  • schedule.idid

Check or alter the ID of the named area.

  • schedule.hexesarray of locations

Get the list of locations the area affects, or assign a new list of locations. The list may be empty, in which case the area has no effect on time of day and cannot be matched by a location filter.

wesnoth.map.set_owner

  • wesnoth.map.set_owner(location, side number)

Set the owner of a village hex. If the specified hex is not a village, this has no effect. Set the owner to 0 to leave it owned by no-one.

wesnoth.map.get_owner

  • wesnoth.map.get_owner(location) → side number

Get the owner of a village hex. If the specified hex is not a village, or if it is an unclaimed village, this returns 0.

wesnoth.map.create

  • wesnoth.map.create(width, height, terrain) → map
  • wesnoth.map.create(map data string) → map

Create a new map, either filled with a given terrain or read from a string.

wesnoth.map.generate

  • wesnoth.map.generate(width, height, options) → map

Generate a map using the default generator. The following options are supported:

  • nplayers
  • nvillages
  • iterations
  • hill_size
  • castle_size
  • island_size
  • island_off_center
  • max_lakes
  • link_castles
  • seed

wesnoth.map.generate_height_map

  • wesnoth.map.generate_height_map(width, height, options) → array of heights

Generates a height map such as that used by the default generator. The following options are supported:

  • iterations
  • hill_size
  • island_size
  • center_x
  • center_y
  • flip_format
  • seed

wesnoth.map.get_direction

  • wesnoth.map.get_direction(from, dir, [steps]) → location

Calculates the hex reached by travelling in the specified direction, which should be a string such as "ne" or "s". It will also honor direction modifiers (the prefix - and postfix :cw or :ccw). The optional third parameter steps is number of steps to travel in specified direction. Negative steps is supported to travel in the opposite direction.

wesnoth.map.get_relative_dir

  • wesnoth.map.get_relative_dir(from, to) → direction

Calculates the direction from one hex to another. Possible returns are strings "n", "ne", "nw", "s", "se", "sw" or "". The empty string means no direction, which happens if from and to are same.

wesnoth.map.rotate_right_around_center

  • wesnoth.map.rotate_right_around_center(loc, center, angle) → location

Calculates the hex obtained from rotating the specified location around the specified center by the specified angle. The angle is an integer in the range 1..6.

wesnoth.map.get_adjacent_hexes

  • wesnoth.map.get_adjacent_hexes(loc) → n, ne, se, s, sw, nw

Return all hexes adjacent to the specified hex, as six separate return values. This doesn't check whether the hexes are on the map.

local a, b, c, d, e, f = wesnoth.map.get_adjacent_hexes(3, 3)
local a_x = a[1]
local a_y = a[2]

wesnoth.map.get_hexes_in_radius

  • wesnoth.map.get_hexes_in_radius(center, radius) → list of locations

Return all hexes within the given radius, as an array of pairs. This doesn't check whether the hexes are on the map.

wesnoth.map.are_hexes_adjacent

  • wesnoth.map.are_hexes_adjacent(loc1, loc2) → boolean

Tests if two hexes are adjacent.

wesnoth.map.distance_between

  • wesnoth.map.distance_between(loc1, loc2) → integer

Calculates the distance between two hexes. The distance is the number of hexes you would need to travel across to get from the start point to the end point.

local my_distance = wesnoth.map.distance_between({10, 10}, {20, 20})