A map's own interface

A map can draw its own panels on the players' screens from Go, in the game's style: text, buttons, panels that hold them, quests in the quest panel, and slash commands in the chat. The game shows each element to the players it is for and sends clicks back to the script, which runs inside the simulation. That is also how it will work over a network. The concepts are on Commands and interface; this page builds something with them.

Anchors and ids

Every element has an id and a player. Calling a function again with the same id replaces the element; player.Everyone as the player shows it to all players, one player such as player.Red to just them. Positions are an anchor (a corner, an edge or the centre of the screen) and an offset inwards from it, in the interface's 1080-pixel units, so a layout looks the same on every screen size.

ui.Text(player.Everyone, "title", "Welcome to the arena", ui.Top, 0, 20, ui.Size(26), ui.Color("ffd27a"))

puts a large golden line twenty pixels down from the top centre.

A shop

A panel at the bottom with a button that buys a unit for gold:

package main

import (
	"fmt"

	"w4/event"
	"w4/game"
	"w4/player"
	"w4/ui"
)

var gold = map[player.ID]int{player.Red: 100, player.Blue: 100}

func showGold(p player.ID) {
	ui.Text(p, "gold", fmt.Sprintf("Gold: %d", gold[p]), ui.TopRight, 24, 60, ui.Size(20))
}

func main() {
	event.OnMapInit(func() {
		for _, who := range []player.ID{player.Red, player.Blue} {
			showGold(who)
			ui.Panel(who, "shop", ui.Bottom, 0, 130, 300, 90)
			ui.Text(who, "shop.title", "Shop", ui.Top, 0, 10, ui.In("shop"), ui.Size(18))
			ui.Button(who, "shop.footman", "Footman (50)", ui.Bottom, 0, 14, func(p player.ID) {
				if gold[p] < 50 {
					game.Printf("%v: not enough gold", p)
					return
				}
				gold[p] -= 50
				showGold(p)
				game.SpawnUnit("Footman", -512+float64(p)*512, 0, p)
			}, ui.In("shop"))
		}
	})
}

ui.In("shop") places an element inside the panel: its anchor and offsets are then the panel's, not the screen's. The click handler gets the player who clicked, and because the handler runs in the simulation, every player's game agrees on the gold.

The gold here is the script's own; the game's gold (the number at the top of the screen, which training and building spend) is not yet readable from Go.

Hide and show

ui.Hide(player, "shop") takes the panel off the screen with everything in it, ui.Show brings it back, ui.Remove deletes it for good. A command to toggle it:

shown := true
game.Command("shop", "", "Shows or hides the shop", func(p player.ID, args string) {
	if shown {
		ui.Hide(p, "shop")
	} else {
		ui.Show(p, "shop")
	}
	shown = !shown
})

Type /shop in the chat (Enter, then the line). Map commands appear in /help with the help text you gave and in the autocompletion list as you type.

Quests

ui.Quest(player.Everyone, "survive", "Survive", "Hold out for ten minutes")
// later
ui.QuestDone("survive")   // stays in the panel, in green
ui.QuestFailed("survive") // in red

The quest panel sits in the column at the right under the top bar, beside the allies panel.

Hiding the whole interface

Players can hide everything, the game's panels, the minimap and your elements, with Ctrl H or /hideui, for a screenshot; opening the chat shows it all again.

Not yet

Images, progress bars, text input and tooltips for map elements are planned; the API page says what exists today: package ui.