M1d: Stilproben #12
@@ -38,3 +38,15 @@ SAVE_UNREADABLE,Der Spielstand lässt sich gerade nicht lesen,The save cannot be
|
|||||||
STYLE_WARM,Warm,Warm
|
STYLE_WARM,Warm,Warm
|
||||||
STYLE_PASTEL,Pastell,Pastel
|
STYLE_PASTEL,Pastell,Pastel
|
||||||
STYLE_GLOW,Glimmen,Glow
|
STYLE_GLOW,Glimmen,Glow
|
||||||
|
MENU_SHOWCASE,Stilproben ansehen,See the style samples
|
||||||
|
SHOWCASE_TITLE,Stilprobe: %s,Style sample: %s
|
||||||
|
SHOWCASE_BACK,Zurück,Back
|
||||||
|
SHOWCASE_ROCK,Weicher und harter Fels,Soft and hard rock
|
||||||
|
SHOWCASE_DEAD_SOIL,Toter Boden,Dead soil
|
||||||
|
SHOWCASE_LIVING_SOIL,Lebendiger Boden,Living soil
|
||||||
|
SHOWCASE_MOSS,Lebensmoos,Life moss
|
||||||
|
SHOWCASE_PLANT,Faserpflanze wächst,A fibre plant grows
|
||||||
|
SHOWCASE_GRAZER,Weidetier,Grazer
|
||||||
|
SHOWCASE_VINE,Ranke trägt Steine,A vine carries stones
|
||||||
|
SHOWCASE_RUIN,Ruine erwacht,A ruin wakes
|
||||||
|
SHOWCASE_FIGURES,Spielfiguren,Player figures
|
||||||
|
|||||||
|
@@ -13,6 +13,11 @@ static func install() -> void:
|
|||||||
_add_keys("save_game", [KEY_F5])
|
_add_keys("save_game", [KEY_F5])
|
||||||
_add_keys("load_game", [KEY_F9])
|
_add_keys("load_game", [KEY_F9])
|
||||||
_add_keys("toggle_pause", [KEY_ESCAPE])
|
_add_keys("toggle_pause", [KEY_ESCAPE])
|
||||||
|
_add_keys("next_style", [KEY_F2])
|
||||||
|
_add_keys("back", [KEY_ESCAPE])
|
||||||
|
_add_keys("style_1", [KEY_1])
|
||||||
|
_add_keys("style_2", [KEY_2])
|
||||||
|
_add_keys("style_3", [KEY_3])
|
||||||
_add_mouse_button("dig", MOUSE_BUTTON_LEFT)
|
_add_mouse_button("dig", MOUSE_BUTTON_LEFT)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ var clock: TickClock
|
|||||||
## The style the playing field is drawn in.
|
## The style the playing field is drawn in.
|
||||||
var art: Art
|
var art: Art
|
||||||
var menu: Menu
|
var menu: Menu
|
||||||
|
var showcase: Showcase
|
||||||
var map_view: MapView
|
var map_view: MapView
|
||||||
var marker: TileMarker
|
var marker: TileMarker
|
||||||
var avatar: Avatar
|
var avatar: Avatar
|
||||||
@@ -103,8 +104,16 @@ func _ready() -> void:
|
|||||||
add_child(menu)
|
add_child(menu)
|
||||||
menu.name_field.text = options.player_name if not options.player_name.is_empty() else store.player_name()
|
menu.name_field.text = options.player_name if not options.player_name.is_empty() else store.player_name()
|
||||||
menu.address_field.text = options.address if not options.address.is_empty() else store.last_address()
|
menu.address_field.text = options.address if not options.address.is_empty() else store.last_address()
|
||||||
|
art.changed.connect(_redraw_art)
|
||||||
menu.play_chosen.connect(play)
|
menu.play_chosen.connect(play)
|
||||||
menu.join_chosen.connect(join)
|
menu.join_chosen.connect(join)
|
||||||
|
menu.showcase_chosen.connect(open_showcase)
|
||||||
|
showcase = Showcase.new()
|
||||||
|
showcase.art = art
|
||||||
|
showcase.closed.connect(close_showcase)
|
||||||
|
showcase.hide()
|
||||||
|
showcase.process_mode = Node.PROCESS_MODE_DISABLED
|
||||||
|
add_child(showcase)
|
||||||
_show_menu("")
|
_show_menu("")
|
||||||
match options.start:
|
match options.start:
|
||||||
"solo":
|
"solo":
|
||||||
@@ -223,6 +232,28 @@ func _show_world() -> void:
|
|||||||
_own_hits.clear()
|
_own_hits.clear()
|
||||||
|
|
||||||
|
|
||||||
|
## Shows the style samples instead of the menu.
|
||||||
|
func open_showcase() -> void:
|
||||||
|
menu.hide()
|
||||||
|
showcase.time = 0.0
|
||||||
|
showcase.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
showcase.show()
|
||||||
|
|
||||||
|
|
||||||
|
## Goes back from the style samples to the menu.
|
||||||
|
func close_showcase() -> void:
|
||||||
|
showcase.hide()
|
||||||
|
showcase.process_mode = Node.PROCESS_MODE_DISABLED
|
||||||
|
menu.show()
|
||||||
|
|
||||||
|
|
||||||
|
## Draws the playing field again after the style changed.
|
||||||
|
func _redraw_art() -> void:
|
||||||
|
map_view.redraw()
|
||||||
|
for node: Node2D in [marker, figures, avatar]:
|
||||||
|
node.queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
## Says in the status line how the game is shared, and with how many.
|
## Says in the status line how the game is shared, and with how many.
|
||||||
func _update_status() -> void:
|
func _update_status() -> void:
|
||||||
if link == null:
|
if link == null:
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
class_name Menu
|
class_name Menu
|
||||||
extends CanvasLayer
|
extends CanvasLayer
|
||||||
## The start screen: the player's name, then playing alone, opening the world
|
## The start screen: the player's name, then playing alone, opening the world
|
||||||
## for guests, or joining a host.
|
## for guests, or joining a host. Below, the way to the style samples.
|
||||||
|
|
||||||
signal play_chosen(open: bool)
|
signal play_chosen(open: bool)
|
||||||
signal join_chosen(address: String)
|
signal join_chosen(address: String)
|
||||||
|
signal showcase_chosen
|
||||||
|
|
||||||
var name_field := LineEdit.new()
|
var name_field := LineEdit.new()
|
||||||
var address_field := LineEdit.new()
|
var address_field := LineEdit.new()
|
||||||
var solo_button := Button.new()
|
var solo_button := Button.new()
|
||||||
var host_button := Button.new()
|
var host_button := Button.new()
|
||||||
var join_button := Button.new()
|
var join_button := Button.new()
|
||||||
|
var showcase_button := Button.new()
|
||||||
var _status := Label.new()
|
var _status := Label.new()
|
||||||
|
|
||||||
|
|
||||||
@@ -39,15 +41,17 @@ func _ready() -> void:
|
|||||||
row.add_child(button)
|
row.add_child(button)
|
||||||
address_field.placeholder_text = tr("MENU_ADDRESS")
|
address_field.placeholder_text = tr("MENU_ADDRESS")
|
||||||
join_button.text = tr("MENU_JOIN")
|
join_button.text = tr("MENU_JOIN")
|
||||||
|
showcase_button.text = tr("MENU_SHOWCASE")
|
||||||
_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
_status.custom_minimum_size = Vector2(380, 0)
|
_status.custom_minimum_size = Vector2(380, 0)
|
||||||
for control: Control in [title, name_field, row, HSeparator.new(), address_field, join_button, _status]:
|
for control: Control in [title, name_field, row, HSeparator.new(), address_field, join_button, HSeparator.new(), showcase_button, _status]:
|
||||||
box.add_child(control)
|
box.add_child(control)
|
||||||
|
|
||||||
solo_button.pressed.connect(func() -> void: play_chosen.emit(false))
|
solo_button.pressed.connect(func() -> void: play_chosen.emit(false))
|
||||||
host_button.pressed.connect(func() -> void: play_chosen.emit(true))
|
host_button.pressed.connect(func() -> void: play_chosen.emit(true))
|
||||||
join_button.pressed.connect(func() -> void: join_chosen.emit(address_field.text.strip_edges()))
|
join_button.pressed.connect(func() -> void: join_chosen.emit(address_field.text.strip_edges()))
|
||||||
address_field.text_submitted.connect(func(_text: String) -> void: join_button.pressed.emit())
|
address_field.text_submitted.connect(func(_text: String) -> void: join_button.pressed.emit())
|
||||||
|
showcase_button.pressed.connect(func() -> void: showcase_chosen.emit())
|
||||||
|
|
||||||
|
|
||||||
## Shows `text` below the buttons.
|
## Shows `text` below the buttons.
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
class_name Showcase
|
||||||
|
extends CanvasLayer
|
||||||
|
## The showcase of the style samples: one small scene in the chosen style,
|
||||||
|
## with the terrain of the test map and things of later milestones. Dead
|
||||||
|
## soil turns living, moss glows, a vine carries stones into a waking ruin, a
|
||||||
|
## plant grows and an animal hops. Buttons switch the style.
|
||||||
|
|
||||||
|
## The player wants to go back to the menu.
|
||||||
|
signal closed
|
||||||
|
|
||||||
|
## The scene, one letter per tile: B edge of the map, S soft rock, H hard
|
||||||
|
## rock, . dead soil, L living soil.
|
||||||
|
const GRID: Array[String] = [
|
||||||
|
"BBSSSHHH............",
|
||||||
|
"BSSSHHH.............",
|
||||||
|
"SS...H..............",
|
||||||
|
"..........LLLLLL....",
|
||||||
|
".......LLLLLLLLLLLL.",
|
||||||
|
".....LLLLLLLLLLLLLL.",
|
||||||
|
".....LLLLLLLLLLLLLL.",
|
||||||
|
".......LLLLLLLLLLL..",
|
||||||
|
".........LLLLLL.....",
|
||||||
|
"....................",
|
||||||
|
]
|
||||||
|
## Pixels of the scene per pixel on screen.
|
||||||
|
const ZOOM := 3.0
|
||||||
|
## Seconds from seed to grown plant, and the pause before it starts again.
|
||||||
|
const GROW_SECONDS := 6.0
|
||||||
|
const GROWN_SECONDS := 2.0
|
||||||
|
## Seconds between two hops, and how long a hop lasts.
|
||||||
|
const HOP_EVERY := 1.2
|
||||||
|
const HOP_SECONDS := 0.5
|
||||||
|
## How far stones travel along the vine per second, as a share of its length.
|
||||||
|
const STONE_SPEED := 0.1
|
||||||
|
const STONES := 3
|
||||||
|
## The path of the vine, in tiles: along the living soil into the ruin.
|
||||||
|
const VINE: Array[Vector2] = [
|
||||||
|
Vector2(6.8, 6.9), Vector2(9.0, 7.3), Vector2(11.0, 6.9),
|
||||||
|
Vector2(13.0, 7.1), Vector2(15.0, 6.4), Vector2(17.3, 5.7),
|
||||||
|
]
|
||||||
|
## Where things stand, in tiles: the middle of their foot; for the figures
|
||||||
|
## the middle of the tile they stand on.
|
||||||
|
const MOSS: Array[Vector2] = [Vector2(8.0, 4.6), Vector2(9.8, 3.3), Vector2(14.2, 3.4), Vector2(16.8, 6.8)]
|
||||||
|
const PLANT := Vector2(10.9, 4.4)
|
||||||
|
const GRAZER_HOME := Vector2(12.8, 5.2)
|
||||||
|
## The ruin covers three by three tiles from here.
|
||||||
|
const RUIN := Vector2i(16, 3)
|
||||||
|
## The figures of two players: the own one and one of another colour.
|
||||||
|
const FIGURES: Array[Vector2] = [Vector2(3.0, 5.0), Vector2(1.6, 6.6)]
|
||||||
|
|
||||||
|
var art: Art
|
||||||
|
## Seconds since the showcase opened.
|
||||||
|
var time := 0.0
|
||||||
|
var style_buttons: Array[Button] = []
|
||||||
|
var back_button := Button.new()
|
||||||
|
var _view := ShowcaseView.new()
|
||||||
|
var _title := Label.new()
|
||||||
|
var _captions: Array[Label] = []
|
||||||
|
var _grid_codes := PackedByteArray()
|
||||||
|
var _solid := PackedByteArray()
|
||||||
|
var _living := PackedByteArray()
|
||||||
|
|
||||||
|
|
||||||
|
## The node that draws the scene.
|
||||||
|
class ShowcaseView extends Node2D:
|
||||||
|
var showcase: Showcase
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
showcase.draw_scene(self)
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_read_grid()
|
||||||
|
var background := ColorRect.new()
|
||||||
|
background.color = Color(0.08, 0.08, 0.09)
|
||||||
|
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||||
|
add_child(background)
|
||||||
|
_view.showcase = self
|
||||||
|
_view.scale = Vector2(ZOOM, ZOOM)
|
||||||
|
add_child(_view)
|
||||||
|
_title.add_theme_font_size_override("font_size", 28)
|
||||||
|
_title.position = Vector2(32, 20)
|
||||||
|
add_child(_title)
|
||||||
|
var row := HBoxContainer.new()
|
||||||
|
row.position = Vector2(32, 660)
|
||||||
|
row.add_theme_constant_override("separation", 12)
|
||||||
|
add_child(row)
|
||||||
|
for index in art.styles.size():
|
||||||
|
var button := Button.new()
|
||||||
|
button.text = "%d %s" % [index + 1, tr(art.styles[index].title_key())]
|
||||||
|
button.pressed.connect(func() -> void: art.select(art.styles[index].key()))
|
||||||
|
style_buttons.append(button)
|
||||||
|
row.add_child(button)
|
||||||
|
back_button.text = tr("SHOWCASE_BACK")
|
||||||
|
back_button.pressed.connect(func() -> void: closed.emit())
|
||||||
|
row.add_child(back_button)
|
||||||
|
_add_captions()
|
||||||
|
art.changed.connect(_on_style_changed)
|
||||||
|
_on_style_changed()
|
||||||
|
get_viewport().size_changed.connect(_layout)
|
||||||
|
_layout()
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
time += delta
|
||||||
|
_view.queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if not visible:
|
||||||
|
return
|
||||||
|
for index in mini(3, art.styles.size()):
|
||||||
|
if event.is_action_pressed("style_%d" % (index + 1)):
|
||||||
|
art.select(art.styles[index].key())
|
||||||
|
if event.is_action_pressed("next_style"):
|
||||||
|
art.select_next()
|
||||||
|
elif event.is_action_pressed("back"):
|
||||||
|
closed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
## How far the plant has grown at `seconds`, from 0 (a seed) to 1, over and
|
||||||
|
## over again.
|
||||||
|
static func growth_at(seconds: float) -> float:
|
||||||
|
return clampf(fposmod(seconds, GROW_SECONDS + GROWN_SECONDS) / GROW_SECONDS, 0.0, 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
## How far the animal is through its hop at `seconds`: from 0 when it takes
|
||||||
|
## off to 1 when it lands, then 1 while it rests.
|
||||||
|
static func hop_at(seconds: float) -> float:
|
||||||
|
return clampf(fposmod(seconds, HOP_EVERY) / HOP_SECONDS, 0.0, 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
## Where the animal is at `seconds`, in tiles: it hops around its home.
|
||||||
|
static func grazer_at(seconds: float) -> Vector2:
|
||||||
|
var hops := floorf(seconds / HOP_EVERY) + hop_at(seconds)
|
||||||
|
return GRAZER_HOME + Vector2(cos(hops * 0.9), sin(hops * 0.9) * 0.4)
|
||||||
|
|
||||||
|
|
||||||
|
## How far each stone is along the vine at `seconds`, from 0 to 1.
|
||||||
|
static func stones_at(seconds: float) -> Array[float]:
|
||||||
|
var shares: Array[float] = []
|
||||||
|
for stone in STONES:
|
||||||
|
shares.append(fposmod(seconds * STONE_SPEED + float(stone) / STONES, 1.0))
|
||||||
|
return shares
|
||||||
|
|
||||||
|
|
||||||
|
## How awake the ruin is at `seconds`: it wakes and dozes in slow breaths.
|
||||||
|
static func awake_at(seconds: float) -> float:
|
||||||
|
return 0.65 + 0.35 * sin(seconds * 1.2)
|
||||||
|
|
||||||
|
|
||||||
|
## The texts under the things in the scene, as keys. Tests read them.
|
||||||
|
func caption_keys() -> PackedStringArray:
|
||||||
|
var keys := PackedStringArray()
|
||||||
|
for label in _captions:
|
||||||
|
keys.append(label.get_meta("key"))
|
||||||
|
return keys
|
||||||
|
|
||||||
|
|
||||||
|
## Draws the whole scene onto `canvas`, while it draws.
|
||||||
|
func draw_scene(canvas: CanvasItem) -> void:
|
||||||
|
if art == null:
|
||||||
|
return
|
||||||
|
var size := GridMotion.TILE_SIZE
|
||||||
|
var width := GRID[0].length()
|
||||||
|
var height := GRID.size()
|
||||||
|
for y in height:
|
||||||
|
for x in width:
|
||||||
|
var tile := Vector2i(x, y)
|
||||||
|
var rect := Rect2(Vector2(tile) * size, Vector2(size, size))
|
||||||
|
var code := _grid_codes[y * width + x]
|
||||||
|
var state := {
|
||||||
|
"solid": TileShape.mask(_solid, width, height, tile, false),
|
||||||
|
"living": TileShape.mask(_living, width, height, tile, false),
|
||||||
|
"variant": TileShape.variant(tile),
|
||||||
|
}
|
||||||
|
art.draw(canvas, _id_of(code), rect, state)
|
||||||
|
for at in MOSS:
|
||||||
|
art.draw(canvas, Art.MOSS, _tile_rect(at), {"variant": TileShape.variant(Vector2i(at)), "time": time})
|
||||||
|
var path := PackedVector2Array()
|
||||||
|
for point in VINE:
|
||||||
|
path.append(point * size)
|
||||||
|
art.draw(canvas, Art.VINE, _bounds(path), {"points": path, "time": time})
|
||||||
|
for share in stones_at(time):
|
||||||
|
var at := ArtStyle.along(path, share)
|
||||||
|
art.draw(canvas, Art.STONE, Rect2(at - Vector2(4, 5), Vector2(8, 8)))
|
||||||
|
art.draw(canvas, Art.FIBER_PLANT, _tile_rect(PLANT, Vector2(1.0, 1.8)), {"growth": growth_at(time), "time": time})
|
||||||
|
var grazer := grazer_at(time)
|
||||||
|
var heading := grazer_at(time + 0.1) - grazer
|
||||||
|
art.draw(canvas, Art.GRAZER, _tile_rect(grazer), {"hop": hop_at(time), "facing": 1.0 if heading.x >= 0.0 else -1.0})
|
||||||
|
var ruin := Rect2(Vector2(RUIN) * size, Vector2(3, 3) * size)
|
||||||
|
art.draw(canvas, Art.RUIN, ruin, {"awake": awake_at(time), "time": time})
|
||||||
|
for player in FIGURES.size():
|
||||||
|
var at := (FIGURES[player] + Vector2(0.5, 0.5)) * size
|
||||||
|
art.draw(canvas, Art.FIGURE, Avatar.figure_rect(at), {"player": player, "facing": 1.0, "step": time * 4.0 + player, "moving": true})
|
||||||
|
|
||||||
|
|
||||||
|
func _read_grid() -> void:
|
||||||
|
var codes := {".": 0, "L": 1, "S": 2, "H": 3, "B": 4}
|
||||||
|
_grid_codes.clear()
|
||||||
|
for line in GRID:
|
||||||
|
for letter in line:
|
||||||
|
_grid_codes.append(codes[letter])
|
||||||
|
_solid = TileShape.flags(_grid_codes, [2, 3, 4])
|
||||||
|
_living = TileShape.flags(_grid_codes, [1])
|
||||||
|
|
||||||
|
|
||||||
|
static func _id_of(code: int) -> StringName:
|
||||||
|
return [Art.DEAD_SOIL, Art.LIVING_SOIL, Art.SOFT_ROCK, Art.HARD_ROCK, Art.BEDROCK][code]
|
||||||
|
|
||||||
|
|
||||||
|
## A square of one tile, or of `size` tiles, whose bottom middle stands at
|
||||||
|
## `at` (in tiles) plus half a tile.
|
||||||
|
static func _tile_rect(at: Vector2, size := Vector2.ONE) -> Rect2:
|
||||||
|
var tile := GridMotion.TILE_SIZE
|
||||||
|
var foot := (at + Vector2(0.5, 1.0)) * tile
|
||||||
|
return Rect2(foot - Vector2(size.x * 0.5, size.y) * tile, size * tile)
|
||||||
|
|
||||||
|
|
||||||
|
static func _bounds(points: PackedVector2Array) -> Rect2:
|
||||||
|
var rect := Rect2(points[0], Vector2.ZERO)
|
||||||
|
for point in points:
|
||||||
|
rect = rect.expand(point)
|
||||||
|
return rect
|
||||||
|
|
||||||
|
|
||||||
|
func _add_captions() -> void:
|
||||||
|
var entries := [
|
||||||
|
["SHOWCASE_ROCK", Vector2(4.0, 3.1)],
|
||||||
|
["SHOWCASE_DEAD_SOIL", Vector2(2.6, 8.8)],
|
||||||
|
["SHOWCASE_LIVING_SOIL", Vector2(12.5, 9.15)],
|
||||||
|
["SHOWCASE_MOSS", Vector2(8.4, 5.6)],
|
||||||
|
["SHOWCASE_PLANT", Vector2(11.4, 2.3)],
|
||||||
|
["SHOWCASE_GRAZER", Vector2(13.3, 6.3)],
|
||||||
|
["SHOWCASE_VINE", Vector2(10.6, 7.7)],
|
||||||
|
["SHOWCASE_RUIN", Vector2(17.5, 1.9)],
|
||||||
|
["SHOWCASE_FIGURES", Vector2(2.6, 7.7)],
|
||||||
|
]
|
||||||
|
for entry: Array in entries:
|
||||||
|
var label := Label.new()
|
||||||
|
label.text = tr(entry[0])
|
||||||
|
label.set_meta("key", entry[0])
|
||||||
|
label.set_meta("at", entry[1])
|
||||||
|
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
label.add_theme_font_size_override("font_size", 13)
|
||||||
|
label.add_theme_color_override("font_outline_color", Color(0.05, 0.05, 0.06))
|
||||||
|
label.add_theme_constant_override("outline_size", 5)
|
||||||
|
_captions.append(label)
|
||||||
|
add_child(label)
|
||||||
|
|
||||||
|
|
||||||
|
## Puts the scene in the middle of the screen and the texts under their
|
||||||
|
## things.
|
||||||
|
func _layout() -> void:
|
||||||
|
var scene_size := Vector2(GRID[0].length(), GRID.size()) * GridMotion.TILE_SIZE * ZOOM
|
||||||
|
var screen := get_viewport().get_visible_rect().size
|
||||||
|
_view.position = ((screen - scene_size) / 2.0).floor()
|
||||||
|
for label in _captions:
|
||||||
|
var at: Vector2 = label.get_meta("at")
|
||||||
|
label.size = Vector2(160, 20)
|
||||||
|
label.position = _view.position + at * GridMotion.TILE_SIZE * ZOOM - Vector2(80, 0)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_style_changed() -> void:
|
||||||
|
_title.text = tr("SHOWCASE_TITLE") % tr(art.style.title_key())
|
||||||
|
for index in style_buttons.size():
|
||||||
|
style_buttons[index].disabled = art.styles[index] == art.style
|
||||||
|
_view.queue_redraw()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bscs3cghniuuq
|
||||||
@@ -3,7 +3,7 @@ extends TestCase
|
|||||||
|
|
||||||
func test_every_action_of_the_game_exists() -> void:
|
func test_every_action_of_the_game_exists() -> void:
|
||||||
InputSetup.install()
|
InputSetup.install()
|
||||||
for action in ["move_up", "move_down", "move_left", "move_right", "dig", "save_game", "load_game", "toggle_pause"]:
|
for action in ["move_up", "move_down", "move_left", "move_right", "dig", "save_game", "load_game", "toggle_pause", "next_style", "back", "style_1", "style_2", "style_3"]:
|
||||||
check(InputMap.has_action(action), "action %s" % action)
|
check(InputMap.has_action(action), "action %s" % action)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -425,3 +425,18 @@ func test_own_hits_reported_late_show_no_second_burst() -> void:
|
|||||||
main._apply(reports)
|
main._apply(reports)
|
||||||
check_eq(main.map_view.burst_count(), 2, "two own hits, two bursts")
|
check_eq(main.map_view.burst_count(), 2, "two own hits, two bursts")
|
||||||
_clean_up([directory])
|
_clean_up([directory])
|
||||||
|
|
||||||
|
|
||||||
|
func test_the_style_samples_open_from_the_menu_and_lead_back_to_it() -> void:
|
||||||
|
var directory := TestFiles.temporary_dir("showcase")
|
||||||
|
var main := _start_main(directory)
|
||||||
|
main.menu.showcase_button.pressed.emit()
|
||||||
|
check(main.showcase.visible, "the samples show")
|
||||||
|
check(not main.menu.visible, "instead of the menu")
|
||||||
|
main.showcase.style_buttons[2].pressed.emit()
|
||||||
|
check_eq(main.art.style.key(), GlowStyle.KEY, "a button there chooses the style")
|
||||||
|
await tree.process_frame
|
||||||
|
main.showcase.back_button.pressed.emit()
|
||||||
|
check(main.menu.visible, "the menu is back")
|
||||||
|
check(not main.showcase.visible, "the samples are gone")
|
||||||
|
_clean_up([directory])
|
||||||
|
|||||||
@@ -35,3 +35,13 @@ func test_the_name_and_the_status_line() -> void:
|
|||||||
check_eq(menu.status(), "Verbinde …", "the status is shown")
|
check_eq(menu.status(), "Verbinde …", "the status is shown")
|
||||||
check_eq(menu.solo_button.text, tr("MENU_SOLO"), "the labels come from the texts")
|
check_eq(menu.solo_button.text, tr("MENU_SOLO"), "the labels come from the texts")
|
||||||
_free(menu)
|
_free(menu)
|
||||||
|
|
||||||
|
|
||||||
|
func test_the_way_to_the_style_samples() -> void:
|
||||||
|
var menu := _menu()
|
||||||
|
var chosen := [0]
|
||||||
|
menu.showcase_chosen.connect(func() -> void: chosen[0] += 1)
|
||||||
|
check_eq(menu.showcase_button.text, tr("MENU_SHOWCASE"), "the button says where it leads")
|
||||||
|
menu.showcase_button.pressed.emit()
|
||||||
|
check_eq(chosen[0], 1, "it asks for the samples")
|
||||||
|
_free(menu)
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
extends TestCase
|
||||||
|
## The showcase of the style samples: how its things move, and that it shows
|
||||||
|
## every style.
|
||||||
|
|
||||||
|
|
||||||
|
func test_the_plant_grows_from_a_seed_and_starts_again() -> void:
|
||||||
|
check_eq(Showcase.growth_at(0.0), 0.0, "a seed at first")
|
||||||
|
check(is_equal_approx(Showcase.growth_at(Showcase.GROW_SECONDS / 2.0), 0.5), "half grown halfway")
|
||||||
|
check_eq(Showcase.growth_at(Showcase.GROW_SECONDS), 1.0, "grown")
|
||||||
|
check_eq(Showcase.growth_at(Showcase.GROW_SECONDS + Showcase.GROWN_SECONDS - 0.01), 1.0, "it stays grown for a while")
|
||||||
|
check_eq(Showcase.growth_at(Showcase.GROW_SECONDS + Showcase.GROWN_SECONDS), 0.0, "then a seed again")
|
||||||
|
|
||||||
|
|
||||||
|
func test_the_animal_hops_then_rests_near_its_home() -> void:
|
||||||
|
check_eq(Showcase.hop_at(0.0), 0.0, "taking off")
|
||||||
|
check(is_equal_approx(Showcase.hop_at(Showcase.HOP_SECONDS / 2.0), 0.5), "in the air")
|
||||||
|
check_eq(Showcase.hop_at(Showcase.HOP_SECONDS), 1.0, "landed")
|
||||||
|
check_eq(Showcase.hop_at(Showcase.HOP_EVERY - 0.01), 1.0, "resting until the next hop")
|
||||||
|
for tenth in 100:
|
||||||
|
var at := Showcase.grazer_at(tenth * 0.1)
|
||||||
|
check(at.distance_to(Showcase.GRAZER_HOME) <= 1.01, "near home at %.1f s: %s" % [tenth * 0.1, at])
|
||||||
|
|
||||||
|
|
||||||
|
func test_stones_travel_along_the_vine_one_after_another() -> void:
|
||||||
|
var start := Showcase.stones_at(0.0)
|
||||||
|
check_eq(start.size(), Showcase.STONES, "every stone")
|
||||||
|
check_eq(start[0], 0.0, "the first one starts")
|
||||||
|
for stone in start:
|
||||||
|
check(stone >= 0.0 and stone < 1.0, "on the vine: %f" % stone)
|
||||||
|
var later := Showcase.stones_at(1.0)
|
||||||
|
check(is_equal_approx(later[0], Showcase.STONE_SPEED), "it moves on")
|
||||||
|
var round_trip := Showcase.stones_at(1.0 / Showcase.STONE_SPEED)
|
||||||
|
check(is_equal_approx(round_trip[0], 0.0) or is_equal_approx(round_trip[0], 1.0), "and comes round again")
|
||||||
|
|
||||||
|
|
||||||
|
func test_the_ruin_wakes_and_dozes() -> void:
|
||||||
|
for tenth in 100:
|
||||||
|
var awake := Showcase.awake_at(tenth * 0.1)
|
||||||
|
check(awake >= 0.29 and awake <= 1.0, "between dozing and awake: %f" % awake)
|
||||||
|
|
||||||
|
|
||||||
|
func test_the_showcase_shows_every_style_and_names_its_things() -> void:
|
||||||
|
I18n.install()
|
||||||
|
InputSetup.install()
|
||||||
|
var art := Art.new()
|
||||||
|
var showcase := Showcase.new()
|
||||||
|
showcase.art = art
|
||||||
|
tree.root.add_child(showcase)
|
||||||
|
for index in art.styles.size():
|
||||||
|
showcase.style_buttons[index].pressed.emit()
|
||||||
|
check_eq(art.style, art.styles[index], "button %d chooses its style" % (index + 1))
|
||||||
|
check(showcase.style_buttons[index].disabled, "the chosen one cannot be pressed again")
|
||||||
|
await tree.process_frame
|
||||||
|
for key in showcase.caption_keys():
|
||||||
|
check(tr(key) != key, "a text for %s" % key)
|
||||||
|
var closed := [0]
|
||||||
|
showcase.closed.connect(func() -> void: closed[0] += 1)
|
||||||
|
showcase.back_button.pressed.emit()
|
||||||
|
check_eq(closed[0], 1, "back leads away")
|
||||||
|
tree.root.remove_child(showcase)
|
||||||
|
showcase.free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bx2nja50aj8ju
|
||||||
Reference in New Issue
Block a user