0.4.0: map (N) that fills in as you explore and a compass (closes #1); Old Tam's seam and Cove tips (voiced); the journey and sea fish in the guide; trailer with the tunnel and the Cove; protocol 16
This commit is contained in:
@@ -566,6 +566,11 @@ func _process(delta: float) -> void:
|
||||
if _spoil_left <= 0.0:
|
||||
_spoil_left = SPOIL_EVERY
|
||||
spoil_all()
|
||||
if not server_mode:
|
||||
_explore_left -= delta
|
||||
if _explore_left <= 0.0:
|
||||
_explore_left = 0.5
|
||||
explore(player.global_position)
|
||||
if not Saves.has_world() or get_tree().paused:
|
||||
return
|
||||
_session_time += delta
|
||||
@@ -601,6 +606,7 @@ func save_now() -> bool:
|
||||
func _exit_tree() -> void:
|
||||
if server_mode and Saves.has_world() and _session_time > 0.0:
|
||||
save_now()
|
||||
save_online_map()
|
||||
if Guide.world == self:
|
||||
Guide.stop()
|
||||
if Hints.world == self:
|
||||
@@ -676,6 +682,7 @@ func collect_save() -> Dictionary:
|
||||
"barrow": barrow.save_data() if barrow != null else {},
|
||||
"stones": stones.save_data() if stones != null else {},
|
||||
"tunnel": tunnel.to_data() if tunnel != null else {},
|
||||
"map": map_data(),
|
||||
}
|
||||
|
||||
func _shared_state(harvested: Dictionary, regrow: Dictionary, taken: Array, dropped: Array, pieces: Array) -> Dictionary:
|
||||
@@ -823,6 +830,8 @@ func _apply_save(s: Dictionary, with_player: bool) -> void:
|
||||
stones.load_data(s.get("stones", {}))
|
||||
if tunnel != null:
|
||||
tunnel.load_data(s.get("tunnel", {}))
|
||||
if with_player:
|
||||
load_map_data(String(s.get("map", "")))
|
||||
# The bear (bear_range.gd): applied when it's set up, after loading.
|
||||
_saved_bear = s.get("bear", {})
|
||||
if bears != null:
|
||||
@@ -864,6 +873,107 @@ func _physics_process(delta: float) -> void:
|
||||
push_warning("[world] player left the map at %s; respawning" % p)
|
||||
_respawn()
|
||||
|
||||
# --- the map (Gitea issue #1) ---------------------------------------------------
|
||||
# What you've seen of this worldlet, as a grid of MAP_CELLS x MAP_CELLS cells
|
||||
# over the whole chunk, filled in around you as you go (scripts/ui/map_screen.gd
|
||||
# draws it). Saved with the worldlet in single-player; online, on your own
|
||||
# computer per server and worldlet (the server doesn't need to know).
|
||||
|
||||
const MAP_CELLS := 80
|
||||
const SEE_RADIUS := 30.0 ## how far around you the map fills in
|
||||
var explored := PackedByteArray()
|
||||
var _explore_left := 0.0
|
||||
|
||||
func _ensure_map() -> void:
|
||||
if explored.size() != MAP_CELLS * MAP_CELLS:
|
||||
explored = PackedByteArray()
|
||||
explored.resize(MAP_CELLS * MAP_CELLS)
|
||||
|
||||
## The map cell (x, z) falls in.
|
||||
func map_cell(x: float, z: float) -> Vector2i:
|
||||
var k: float = float(MAP_CELLS) / terrain.size
|
||||
return Vector2i(clampi(int((x + terrain.size * 0.5) * k), 0, MAP_CELLS - 1), clampi(int((z + terrain.size * 0.5) * k), 0, MAP_CELLS - 1))
|
||||
|
||||
func seen(x: float, z: float) -> bool:
|
||||
_ensure_map()
|
||||
var c := map_cell(x, z)
|
||||
return explored[c.y * MAP_CELLS + c.x] != 0
|
||||
|
||||
## Fills in the map around `p` (not from down the tunnel: nothing to see).
|
||||
func explore(p: Vector3) -> void:
|
||||
if underground_at(p) or terrain == null or not terrain.built:
|
||||
return
|
||||
_ensure_map()
|
||||
var cell: float = terrain.size / float(MAP_CELLS)
|
||||
var r := int(ceil(SEE_RADIUS / cell))
|
||||
var c := map_cell(p.x, p.z)
|
||||
for dz in range(-r, r + 1):
|
||||
for dx in range(-r, r + 1):
|
||||
var x := c.x + dx
|
||||
var z := c.y + dz
|
||||
if x < 0 or z < 0 or x >= MAP_CELLS or z >= MAP_CELLS:
|
||||
continue
|
||||
if Vector2(dx, dz).length() * cell <= SEE_RADIUS:
|
||||
explored[z * MAP_CELLS + x] = 1
|
||||
|
||||
func map_data() -> String:
|
||||
_ensure_map()
|
||||
return Marshalls.raw_to_base64(explored.compress(FileAccess.COMPRESSION_DEFLATE))
|
||||
|
||||
func load_map_data(s: String) -> void:
|
||||
explored = PackedByteArray()
|
||||
if not s.is_empty():
|
||||
var raw: PackedByteArray = Marshalls.base64_to_raw(s)
|
||||
if not raw.is_empty():
|
||||
explored = raw.decompress(MAP_CELLS * MAP_CELLS, FileAccess.COMPRESSION_DEFLATE)
|
||||
_ensure_map()
|
||||
|
||||
## Online: your map of this server's worldlet, kept on your computer.
|
||||
func _online_map_path() -> String:
|
||||
var key := "%s_%d_%s" % [String(Net.server_info.get("server_name", "server")), int(terrain.noise_seed), worldlet_id()]
|
||||
return "user://maps/%s.map" % key.validate_filename()
|
||||
|
||||
func save_online_map() -> void:
|
||||
if not is_online():
|
||||
return
|
||||
DirAccess.make_dir_recursive_absolute("user://maps")
|
||||
var f := FileAccess.open(_online_map_path(), FileAccess.WRITE)
|
||||
if f != null:
|
||||
f.store_string(map_data())
|
||||
|
||||
func load_online_map() -> void:
|
||||
load_map_data(FileAccess.get_file_as_string(_online_map_path()) if FileAccess.file_exists(_online_map_path()) else "")
|
||||
|
||||
## What the map marks, where you've seen it: [{kind, pos (Vector3), label}].
|
||||
func map_marks() -> Array:
|
||||
var out: Array = []
|
||||
var add := func(kind: String, pos: Vector3, label: String):
|
||||
if seen(pos.x, pos.z):
|
||||
out.append({"kind": kind, "pos": pos, "label": label})
|
||||
if den != null and den.found:
|
||||
add.call("den", den.global_position, "Wolf den")
|
||||
if barrow != null and barrow.found:
|
||||
add.call("barrow", barrow.global_position, "The barrow")
|
||||
if stones != null and stones.found:
|
||||
add.call("stones", stones.global_position, "Standing stones")
|
||||
if tunnel != null:
|
||||
add.call("seam", tunnel.seam_at, "The tunnel" if tunnel.opened else "Cracked seam")
|
||||
if pier != null:
|
||||
add.call("pier", (pier.start + pier.end) * 0.5, "The pier")
|
||||
if sea_cave != null:
|
||||
add.call("cave", sea_cave.global_position, "Sea cave")
|
||||
for piece in all_pieces():
|
||||
var id: String = String(piece.get("item_id"))
|
||||
if piece.is_in_group("bed"):
|
||||
add.call("bed", piece.global_position, ItemDB.item_name(id))
|
||||
elif BuildPiece.is_build(ItemDB.get_item(id)):
|
||||
add.call("build", piece.global_position, "")
|
||||
elif id in ["campfire", "chest", "workbench", "forge", "hearth"]:
|
||||
add.call("camp", piece.global_position, ItemDB.item_name(id))
|
||||
elif id == "grave":
|
||||
add.call("grave", piece.global_position, "Your things")
|
||||
return out
|
||||
|
||||
## In the cliff tunnel (J1): no daylight, no weather, sheltered.
|
||||
func underground_at(p: Vector3) -> bool:
|
||||
return tunnel != null and tunnel.contains(p)
|
||||
@@ -1086,6 +1196,8 @@ func _go_online() -> void:
|
||||
net_sync.name = "NetSync"
|
||||
add_child(net_sync)
|
||||
net_sync.setup(self)
|
||||
load_online_map() # (your map of this server, from your own computer)
|
||||
Net.left.connect(func(_why = ""): save_online_map(), CONNECT_ONE_SHOT)
|
||||
Net.left.connect(_on_net_left)
|
||||
get_tree().auto_accept_quit = false # leave the server cleanly on window close
|
||||
# The island's changes come from the server from now on.
|
||||
|
||||
Reference in New Issue
Block a user