W1: choose a worldlet (New World and Host Game pages, kept once an island exists), worldlet shown in the Load list; Godot .uid files

This commit is contained in:
Paul Bailey
2026-11-06 16:10:32 +00:00
parent db4a659236
commit 68e6d814d9
96 changed files with 292 additions and 11 deletions

View File

@@ -0,0 +1 @@
uid://nx08dmty60ny

View File

@@ -0,0 +1 @@
uid://dsbvhwas6wsxf

View File

@@ -0,0 +1 @@
uid://gj02g6p3xfip

View File

@@ -0,0 +1 @@
uid://dhsyx4mrm28oe

View File

@@ -0,0 +1 @@
uid://cl5ip4achfdwo

View File

@@ -0,0 +1 @@
uid://mjs6qb5p3q1a

View File

@@ -0,0 +1 @@
uid://ciqsy8msggcke

View File

@@ -0,0 +1 @@
uid://cwvlv0fbxhlgj

View File

@@ -0,0 +1 @@
uid://jvcfwahbmdsm

View File

@@ -0,0 +1 @@
uid://d21if6sepl888

View File

@@ -0,0 +1 @@
uid://dk1ge2xxgiev1

1
scripts/core/boot.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://frm15unnr4w5

View File

@@ -0,0 +1 @@
uid://nva2x7o0ggw1

View File

@@ -0,0 +1 @@
uid://cd4pyfn6igpx0

View File

@@ -0,0 +1 @@
uid://jojnurcejyff

View File

@@ -0,0 +1 @@
uid://ctvohlyg6yr5m

1
scripts/core/sfx.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://br583euuk842q

View File

@@ -0,0 +1 @@
uid://3lflq11qfg00

View File

@@ -0,0 +1 @@
uid://co3yk3efstys2

View File

@@ -0,0 +1 @@
uid://ce34amx3oagyx

View File

@@ -0,0 +1 @@
uid://cdxggdwnq1ctn

View File

@@ -0,0 +1 @@
uid://dy6utmjegblry

View File

@@ -0,0 +1 @@
uid://bs230fcuvorft

View File

@@ -0,0 +1 @@
uid://beng43qyj6rke

View File

@@ -0,0 +1 @@
uid://cfailgwvqv2fc

View File

@@ -0,0 +1 @@
uid://x0xva7tw6ind

View File

@@ -0,0 +1 @@
uid://f88v5i7s5e5c

View File

@@ -0,0 +1 @@
uid://ccpmq0ddkoc8g

View File

@@ -0,0 +1 @@
uid://dukt8gme03lsb

View File

@@ -0,0 +1 @@
uid://cpwa4sffdi3nt

View File

@@ -0,0 +1 @@
uid://b8wfmfnhg2edq

View File

@@ -0,0 +1 @@
uid://024u453fdbml

View File

@@ -0,0 +1 @@
uid://cbb3g7cjprhy8

View File

@@ -0,0 +1 @@
uid://br7isyu6hxnsd

View File

@@ -0,0 +1 @@
uid://cs6ucd2nldqmj

View File

@@ -0,0 +1 @@
uid://bccgr18dkfhad

View File

@@ -0,0 +1 @@
uid://w2qc4a4ai4vt

1
scripts/net/chat.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://cj8ew4d4huen5

View File

@@ -0,0 +1 @@
uid://c3amf3mwhetmf

View File

@@ -0,0 +1 @@
uid://x0plvp658wne

View File

@@ -304,14 +304,14 @@ var _host_out := ""
var _host_port := DEFAULT_PORT
## Settings for a hosted game: name, password, port, a rules preset
## (co-op / rivals / adversarial) and the seed for a new island.
## (co-op / rivals / adversarial) and the seed and worldlet for a new island.
const PRESETS := {
"co-op": {"pvp": "false", "raiding": "false", "locks": "owner_and_friends", "death_penalty": "grave"},
"rivals": {"pvp": "true", "raiding": "false", "locks": "owner_and_friends", "death_penalty": "grave"},
"adversarial": {"pvp": "true", "raiding": "true", "locks": "owner", "death_penalty": "drop_all"},
}
func host(server_name: String, password: String, port: int, preset: String, seed: int) -> void:
func host(server_name: String, password: String, port: int, preset: String, seed: int, worldlet: String = "valley") -> void:
if hosting or state != "offline":
return
if _host_pid != 0 and OS.is_process_running(_host_pid):
@@ -324,8 +324,9 @@ func host(server_name: String, password: String, port: int, preset: String, seed
c.data.password = password
c.data.port = port
var fresh := not FileAccess.file_exists(host_config.get_base_dir().path_join("worlds/server-world/meta.json"))
if fresh:
if fresh: # (an island keeps its seed and worldlet once it's made)
c.data.seed = seed
c.data.worldlet = worldlet
c.save()
_host_port = port
var args := PackedStringArray(["--headless"])

1
scripts/net/net.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://d1153ihwyw01t

View File

@@ -0,0 +1 @@
uid://bgyhqtmwppt4g

View File

@@ -0,0 +1 @@
uid://dim4cfgbtabvf

1
scripts/net/rules.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://d2fotty6gceeh

View File

@@ -0,0 +1 @@
uid://cykv4lse4g62a

View File

@@ -0,0 +1 @@
uid://dkdnvh8f18o2x

View File

@@ -0,0 +1 @@
uid://cmk7ho2ij6esq

1
scripts/ui/guide.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://dbijp4r843nyk

View File

@@ -0,0 +1 @@
uid://0npv7fub184o

View File

@@ -0,0 +1 @@
uid://87b73wsdjp7t

View File

@@ -370,6 +370,7 @@ func _host_page() -> Control:
_host_preset.add_item(n)
_host_preset.custom_minimum_size = Vector2(420, 36)
v.add_child(_host_preset)
_host_worldlet = _worldlet_picker(v)
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 10)
var c1 := VBoxContainer.new()
@@ -424,6 +425,7 @@ func _fill_host() -> void:
_host_seed.editable = not existing
_host_seed_label.text = "Seed" if not existing else "Seed (kept)"
_host_seed.text = "" if not existing else str(int(c.data.seed))
_show_host_worldlet(existing, meta_path)
_host_msg.text = "Your hosted island carries on where you left it." if existing else "A new island will be made."
_host_msg.add_theme_color_override("font_color", UITheme.TEXT_DIM)
_host_btn.disabled = false
@@ -439,7 +441,8 @@ func _start_host() -> void:
if name.is_empty():
name = "%s's island" % Net.get_identity().name
_host_btn.disabled = true
Net.host(name, _host_pw.text, int(port_t), PRESET_IDS[maxi(_host_preset.selected, 0)], seed)
Net.host(name, _host_pw.text, int(port_t), PRESET_IDS[maxi(_host_preset.selected, 0)], seed,
picked_worldlet(_host_worldlet))
func _on_host_status(text: String, failed: bool) -> void:
if not _pages["host"].visible:
@@ -591,6 +594,7 @@ func _new_page() -> Control:
_rot_pick.add_item(t[1])
_rot_pick.custom_minimum_size = Vector2(360, 36)
v.add_child(_rot_pick)
_worldlet_pick = _worldlet_picker(v)
var h := HBoxContainer.new()
h.add_theme_constant_override("separation", 10)
h.add_child(_button("Create & Play", _create, 170))
@@ -633,7 +637,8 @@ func _fill_list() -> void:
info.add_child(UITheme.label(w.name, 18))
var played := int(w.get("play_time", 0.0))
var when := Time.get_datetime_string_from_unix_time(int(w.get("last_played", 0)), true)
info.add_child(UITheme.label("seed %d · played %dh %02dm · %s" % [int(w.seed), played / 3600, (played / 60) % 60, when], 13, UITheme.TEXT_DIM))
info.add_child(UITheme.label("%s · seed %d · played %dh %02dm · %s" % [Terrain.worldlet_name(String(w.get("worldlet", "valley"))),
int(w.seed), played / 3600, (played / 60) % 60, when], 13, UITheme.TEXT_DIM))
h.add_child(info)
h.add_child(_button("Play", _play.bind(w.id), 80))
var del := Button.new()
@@ -681,7 +686,68 @@ func _create() -> void:
var seed_text := _seed_edit.text.strip_edges()
var seed := int(seed_text) if seed_text.is_valid_int() else (seed_text.hash() if not seed_text.is_empty() else randi())
var rot: String = ROT_CHOICES[maxi(_rot_pick.selected, 0)][0]
_play(Saves.create_world(world_name, seed, {"rot": rot}))
_play(Saves.create_world(world_name, seed, {"rot": rot, "worldlet": picked_worldlet(_worldlet_pick)}))
# --- worldlets (docs/WORLDLETS_DESIGN.md, W1) -----------------------------------------
const Terrain = preload("res://scripts/world/terrain.gd")
var _worldlet_pick: OptionButton
var _host_worldlet: OptionButton
## "Where": the worldlets a new world can start in, with the chosen one's
## description under it. (Only the Valley today: the others are reached on
## the journey, so the list is short and the picker sits still.)
func _worldlet_picker(v: VBoxContainer) -> OptionButton:
var starts: Array = Terrain.starting_worldlets()
v.add_child(UITheme.label("Where", 15, UITheme.TEXT_DIM))
var pick := OptionButton.new()
pick.custom_minimum_size = Vector2(360, 36)
pick.focus_mode = Control.FOCUS_NONE
for w in starts:
pick.add_item(String(w.name))
pick.set_item_metadata(pick.item_count - 1, String(w.id))
pick.disabled = starts.size() < 2
v.add_child(pick)
var about := UITheme.label(String(starts[0].description) if not starts.is_empty() else "", 13, UITheme.TEXT_DIM)
about.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
about.custom_minimum_size = Vector2(360, 0)
v.add_child(about)
pick.item_selected.connect(func(i: int):
about.text = String(Terrain.load_worldlet(String(pick.get_item_metadata(i))).get("description", "")))
return pick
## The Host page's "Where": a hosted island keeps its worldlet, like its
## seed, so once it exists the picker shows that one and stays put.
func _show_host_worldlet(existing: bool, meta_path: String) -> void:
var id := "valley"
if existing:
var meta: Variant = JSON.parse_string(FileAccess.get_file_as_string(meta_path))
if meta is Dictionary:
id = String(meta.get("worldlet", "valley"))
var i := select_worldlet(_host_worldlet, id)
if i >= 0:
_host_worldlet.item_selected.emit(i)
_host_worldlet.disabled = existing or _host_worldlet.item_count < 2
## Selects worldlet `id` in `pick`, adding it if it isn't a starting one
## (an island made somewhere else). Returns its index, or -1.
static func select_worldlet(pick: OptionButton, id: String) -> int:
for i in pick.item_count:
if String(pick.get_item_metadata(i)) == id:
pick.select(i)
return i
if Terrain.load_worldlet(id).is_empty():
return -1
pick.add_item(Terrain.worldlet_name(id))
pick.set_item_metadata(pick.item_count - 1, id)
pick.select(pick.item_count - 1)
return pick.item_count - 1
## The id of the worldlet chosen in `pick` (the Valley if nothing is).
static func picked_worldlet(pick: OptionButton) -> String:
if pick == null or pick.item_count == 0 or pick.selected < 0:
return "valley"
return String(pick.get_item_metadata(pick.selected))
## The tutorial (docs/TUTORIAL_DESIGN.md): its own world on the original
## island (seed 1337), made the first time and carried on after that.

View File

@@ -0,0 +1 @@
uid://5vs0iggnxpuc

View File

@@ -0,0 +1 @@
uid://bmcefncielej3

View File

@@ -0,0 +1 @@
uid://c4dyxek30amhh

View File

@@ -169,9 +169,20 @@ static func worldlets() -> Array:
if f.ends_with(".json"):
var d := load_worldlet(f.get_basename())
if not d.is_empty():
out.append({"id": String(d.id), "name": String(d.get("name", d.id)), "description": String(d.get("description", ""))})
out.append({"id": String(d.id), "name": String(d.get("name", d.id)), "description": String(d.get("description", "")),
"start": bool(d.get("start", false))})
out.sort_custom(func(a, b): return a.id == "valley" or (b.id != "valley" and a.name < b.name))
return out
## The worldlets a new world can start in (the rest are reached on the journey).
static func starting_worldlets() -> Array:
return worldlets().filter(func(w): return w.start)
## A worldlet's display name ("Valley"), or its id if there's no such worldlet.
static func worldlet_name(id: String) -> String:
var d := load_worldlet(id)
return String(d.get("name", id)) if not d.is_empty() else id
## Takes on worldlet `id`: its size and every block's numbers. Returns ""
## on success, else what's wrong (an unknown worldlet or block keeps the old
## settings, so the game still has an island).

View File

@@ -0,0 +1 @@
uid://b5x4pld4ecyr4

View File

@@ -0,0 +1 @@
uid://ch20dfnan2yed