diff --git a/.vscode/launch.json b/.vscode/launch.json index 87e1ca5d..a3f0fd89 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,7 +18,8 @@ "initCommands": ["command source ${workspaceRoot}/.lldbinit"], "presentation": { "clear": true // <-- this line - } + }, + "console": "internalConsole" }, { "type": "lldb", @@ -44,6 +45,18 @@ "cwd": "${workspaceFolder}", "preLaunchTask": "Build Current File", "initCommands": ["command source ${workspaceRoot}/.lldbinit"], + }, + { + "type": "lldb", + "request": "attach", + "name": "Attatch to Enu", + "program": "${workspaceFolder}/vendor/godot/bin/godot.osx.opt.tools.arm64", + "windows": { + "program": "${workspaceFolder}/vendor/godot/bin/godot.windows.opt.tools.64" + }, + "args": [], + "cwd": "${workspaceFolder}/app", + "initCommands": ["command source ${workspaceRoot}/.lldbinit"], "presentation": { "clear": true // <-- this line } diff --git a/enu.nimble b/enu.nimble index 6aaf7edf..e78b2608 100644 --- a/enu.nimble +++ b/enu.nimble @@ -29,8 +29,9 @@ else: requires "https://github.com/dsrw/Nim#b7cf2e6" requires "nim >= 1.6.10", + "https://github.com/arnetheduck/nim-results#f3c666a", "https://github.com/dsrw/godot-nim#892c482", - "https://github.com/dsrw/model_citizen 0.18.3", + "https://github.com/dsrw/model_citizen 0.18.5", "https://github.com/dsrw/nanoid.nim 0.2.1", "cligen 1.6.0", "https://github.com/treeform/pretty", diff --git a/src/controllers/script_controllers/host_bridge.nim b/src/controllers/script_controllers/host_bridge.nim index 4e69ea34..fa4e122c 100644 --- a/src/controllers/script_controllers/host_bridge.nim +++ b/src/controllers/script_controllers/host_bridge.nim @@ -328,19 +328,6 @@ proc drop_transform(unit: Unit): Transform = else: raise ObjectConversionDefect.init("Unknown unit type") -proc new_markdown_sign(self: Worker, - unit: Unit, pnode: PNode, markdown: string, title: string, width: float, - height: float, size: int, zoomable: bool, billboard: bool): Unit = - - result = Sign.init( - markdown, title = title, owner = self.active_unit, - transform = drop_transform(unit), width = width, height = height, - size = size, zoomable = zoomable, billboard = billboard) - - info "creating sign", id = result.id - self.map_unit(result, pnode) - unit.units.add(result) - proc reset(self: Unit, clear: bool) = if clear: if self of Build: Build(self).reset() @@ -418,17 +405,44 @@ proc `tool=`(self: Unit, value: int) = state.tool = Tools(value) # Sign bindings + +proc new_markdown_sign(self: Worker, + unit: Unit, pnode: PNode, message: string, more: string, width: float, + height: float, size: int, billboard: bool): Unit = + + result = Sign.init( + message, more = more, owner = self.active_unit, + transform = drop_transform(unit), width = width, height = height, + size = size, billboard = billboard) + + info "creating sign", id = result.id + self.map_unit(result, pnode) + unit.units.add(result) + +proc update_markdown_sign(self: Worker, unit: Sign, message: string, + more: string, width: float, height: float, size: int, billboard: bool) = + + unit.width = width + unit.height = height + unit.size = size + unit.billboard = billboard + unit.more = more + unit.message = message + proc `width=`(self: Sign, value: float) = types.`width=`(self, value) - self.title_value.touch self.title + self.message_value.touch self.message proc `height=`(self: Sign, value: float) = types.`height=`(self, value) - self.title_value.touch self.title + self.message_value.touch self.message proc `size=`(self: Sign, value: int) = types.`size=`(self, value) - self.title_value.touch self.title + self.message_value.touch self.message + +proc message(self: Sign): string = + self.message_value.value proc open(self: Sign): bool = state.open_sign == self @@ -464,7 +478,8 @@ proc bridge_to_vm*(worker: Worker) = result.bridged_from_vm "base_bridge_private", link_dependency, action_running, `action_running=`, yield_script, - begin_turn, begin_move, sleep_impl, position_set, new_markdown_sign + begin_turn, begin_move, sleep_impl, position_set, new_markdown_sign, + update_markdown_sign result.bridged_from_vm "bots", play, all_bots @@ -473,8 +488,8 @@ proc bridge_to_vm*(worker: Worker) = drawing, `drawing=`, initial_position, save, restore, all_builds result.bridged_from_vm "signs", - markdown, `markdown=`, title, `title=`, height, `height=`, width, `width=`, - size, `size=`, open, `open=` + message, `message=`, more, `more=`, height, `height=`, width, `width=`, + size, `size=`, open, `open=`, billboard, `billboard=` result.bridged_from_vm "players", playing, `playing=`, god, `god=`, flying, `flying=`, tool, `tool=`, diff --git a/src/controllers/script_controllers/scripting.nim b/src/controllers/script_controllers/scripting.nim index 2771dd77..b1a31d18 100644 --- a/src/controllers/script_controllers/scripting.nim +++ b/src/controllers/script_controllers/scripting.nim @@ -58,9 +58,9 @@ proc init_interpreter*[T](self: Worker, _: T) {.gcsafe.} = if file_name.get_file_info != ctx.file_name.get_file_info: (file_name, info) = extract_file_info msg - msg = msg.replace(re"unhandled exception:.*\) Error\: ", "") - else: - msg = msg.replace(re"(?ms);.*", "") + # msg = msg.replace(re"unhandled exception:.*\) Error\: ", "") + #else: + # msg = msg.replace(re"(?ms);.*", "") var loc = \"{file_name}({int info.line},{int info.col})" error "vm error", msg, file = ctx.file_name @@ -211,4 +211,3 @@ proc eval*(self: Worker, unit: Unit, code: string) = unit.script_ctx.timeout_at = get_mono_time() + script_timeout {.gcsafe.}: discard unit.script_ctx.eval(code) - diff --git a/src/controllers/script_controllers/worker.nim b/src/controllers/script_controllers/worker.nim index c6c9a923..cf287718 100644 --- a/src/controllers/script_controllers/worker.nim +++ b/src/controllers/script_controllers/worker.nim @@ -215,6 +215,9 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = if world_dir != "": save_world(world_dir) worker.unload_world() + if ResettingVM in state.local_flags: + worker.init_interpreter("") + worker.bridge_to_vm world_dir = change.item.world_dir if world_dir != "": worker.load_world(world_dir) @@ -229,7 +232,7 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = worker.load_script_and_dependents(player) var sign = Sign.init("", "", width = 3, height = 2.05, owner = state.player, - size = 244, zoomable = true, billboard = true, text_only = true, + size = 244, billboard = true, text_only = true, transform = Transform.init(origin = vec3(0, 3, 0))) state.player.units += sign diff --git a/src/core.nim b/src/core.nim index 771a5d9d..21d81430 100644 --- a/src/core.nim +++ b/src/core.nim @@ -13,7 +13,8 @@ var state* {.threadvar.}: GameState ### Sugar ### from sugar import dup, dump, collect -import std / [with, sets, times, monotimes, tables] +import std / [with, sets, monotimes, tables] +import std / times except seconds import pkg / [pretty, flatty] export with, sets, tables, pretty, flatty @@ -27,13 +28,6 @@ export chronicles template nim_filename*: string = instantiation_info(full_paths = true).filename -### times ### - -export monotimes - -proc seconds*(s: float): Duration {.inline.} = - init_duration(milliseconds = int(s * 1000)) - ### options ### import options diff --git a/src/game.nim b/src/game.nim index 08e6d624..518f4270 100644 --- a/src/game.nim +++ b/src/game.nim @@ -311,9 +311,12 @@ world: {state.world_name} elif event.is_action_released("command_mode"): state.pop_flag CommandMode elif event.is_action_pressed("save_and_reload"): + state.pop_flag Playing + state.push_flag ResettingVM self.switch_world(0) + state.pop_flag ResettingVM self.get_tree().set_input_as_handled() - state.pop_flag Playing + elif event.is_action_pressed("pause"): state.paused = not state.paused elif event.is_action_pressed("clear_console"): diff --git a/src/models/bot_code_template.nim.nimf b/src/models/bot_code_template.nim.nimf index 32d7eb98..3bfb03eb 100644 --- a/src/models/bot_code_template.nim.nimf +++ b/src/models/bot_code_template.nim.nimf @@ -1,9 +1,9 @@ #? stdtmpl #proc bot_code_template(file_name, imports: string): string = +import system except echo, quit import std / [strutils] -import types, class_macros, players, state_machine, base_api, bots, builds, +import types, class_macros, players, state_machine, base_api, bots, builds, signs, bots_private -include overrides let instance_global_by_default = true var move_mode = 1 diff --git a/src/models/build_code_template.nim.nimf b/src/models/build_code_template.nim.nimf index c177af38..288a3805 100644 --- a/src/models/build_code_template.nim.nimf +++ b/src/models/build_code_template.nim.nimf @@ -1,9 +1,9 @@ #? stdtmpl #proc build_code_template(file_name, imports: string): string = +import system except echo, quit import std / [strutils] -import types, class_macros, players, state_machine, base_api, bots, builds, +import types, class_macros, players, state_machine, base_api, bots, builds, signs, builds_private -include overrides let instance_global_by_default = false var move_mode = 1 diff --git a/src/models/players.nim b/src/models/players.nim index 2c22b8af..75e018f0 100644 --- a/src/models/players.nim +++ b/src/models/players.nim @@ -28,7 +28,7 @@ proc open_code*(self: Player): string = for unit in self.units: if unit of Sign: let unit = Sign(unit) - return unit.markdown + return unit.message proc `open_code=`*(self: Player, code: string) = for unit in self.units: @@ -37,6 +37,6 @@ proc `open_code=`*(self: Player, code: string) = if code == "": unit.global_flags -= Visible else: - unit.markdown = code + unit.message = code unit.global_flags += Visible return diff --git a/src/models/serializers.nim b/src/models/serializers.nim index bbbe5272..6333c597 100644 --- a/src/models/serializers.nim +++ b/src/models/serializers.nim @@ -115,7 +115,7 @@ proc `$`(self: Unit): string = "basis": [ {elements.indent(6)} ], - "origin": {self.start_transform.origin} + "origin": {$self.start_transform.origin} }}, "start_color": {self.start_color}, "edits": {{ diff --git a/src/models/signs.nim b/src/models/signs.nim index c55bd69b..cc34cd78 100644 --- a/src/models/signs.nim +++ b/src/models/signs.nim @@ -1,22 +1,19 @@ import godotapi / spatial import core, states, bots, builds, models / [colors, units] -proc init*(_: type Sign, - markdown: string, title = "", owner: Unit, transform = Transform.init, - width = 1.0, height = 1.0, size = 32, billboard = false, - zoomable = true, text_only = false): Sign = +proc init*(_: type Sign, message: string, more = "", owner: Unit, + transform = Transform.init, width = 1.0, height = 1.0, size = 32, + billboard = false, text_only = false): Sign = - let title = if title == "": markdown else: title var self = Sign( id: "sign_" & generate_id(), - markdown_value: ~markdown, - title_value: ~title, + message_value: ~message, + more_value: ~more, glow_value: ~0.0, width_value: ~width, height_value: ~height, size_value: ~size, billboard_value: ~billboard, - zoomable_value: ~zoomable, frame_created: state.frame_count, color_value: ~action_colors[black], start_transform: transform, diff --git a/src/models/units.nim b/src/models/units.nim index 5cf158c9..30823d1f 100644 --- a/src/models/units.nim +++ b/src/models/units.nim @@ -1,4 +1,4 @@ -import std / [os, sugar, with, tables] +import std / [os, with, tables] import godotapi / spatial from pkg / core / godotcoretypes import Basis import core, models / [states, colors], libs / interpreters @@ -125,10 +125,12 @@ method off_collision*(self: Model, partner: Model) {.base, gcsafe.} = proc destroy*[T: Unit](self: T) = ensure ?self - if self of Sign: # :( Sign(self) will fail to compile if T is a Build or a Bot. Sign(Unit(self)).owner = nil + for unit in self.units: + if unit of Sign: + Sign(Unit(unit)).owner = nil # :( Parent isn't set properly for instances on the main thread if self.parent == nil and "instance" notin self.id: @@ -148,6 +150,7 @@ proc destroy*[T: Unit](self: T) = if state.open_unit == self: state.open_unit = nil + if Unit(state.open_sign) == self: state.open_sign = nil diff --git a/src/nodes/aim_target.nim b/src/nodes/aim_target.nim index 4ffaa80d..9b2426b4 100644 --- a/src/nodes/aim_target.nim +++ b/src/nodes/aim_target.nim @@ -50,7 +50,7 @@ gdobj AimTarget of Sprite3D: state.pop_flag BlockTargetVisible self.target_model = unit # :( - if not (unit == nil or (unit of Sign and not Sign(unit).zoomable) or + if not (unit == nil or (unit of Sign and Sign(unit).more == "") or (God notin state.local_flags and (unit of Bot or unit of Build) and Lock in Unit(unit).find_root.global_flags)): diff --git a/src/nodes/sign_node.nim b/src/nodes/sign_node.nim index a4065a6d..a8a73f22 100644 --- a/src/nodes/sign_node.nim +++ b/src/nodes/sign_node.nim @@ -5,10 +5,20 @@ import godotapi / [spatial, resource_loader, packed_scene, collision_shape, import ui / [markdown_label, editor] import core +const + viewport_x = 1200 + viewport_y = 1200 + gdobj SignNode of Spatial: var model*: Sign var zid: ZID var material: SpatialMaterial + var viewport: Viewport + var label: MarkdownLabel + var shape: CollisionShape + var quad: QuadMesh + var counter: int + var expanded: bool proc set_visibility = if Hide in self.model.local_flags: @@ -22,15 +32,31 @@ gdobj SignNode of Spatial: else: self.visible = false + proc expand() = + self.label.rect_min_size = vec2(1200, 0) + self.label.rect_size = vec2(1200, 0) + + # The markdown label has extra padding at the bottom. There's probably a + # good reason for this and a way to remove it properly, but this gets + # the job done for now. + let padding = self.model.size.float / (0.9 * self.model.width) + let rect = vec2(self.label.rect_size.x, self.label.rect_size.y - padding) + + let ratio = rect.y / rect.x + self.viewport.size = rect + self.quad.size = vec2(self.model.width, self.model.width * ratio) + self.shape.scale = vec3(self.model.width, self.model.width * ratio, 1) + proc setup* = debug "sign setup", sign = self.model.id - var - label = self.get_node("Viewport/MarkdownLabel") as MarkdownLabel - text_edit = self.get_node("Viewport/TextEdit") as TextEdit - shape = self.find_node("CollisionShape") as CollisionShape - mesh = self.find_node("MeshInstance") as MeshInstance - viewport = self.find_node("Viewport") as Viewport - quad = mesh.mesh as QuadMesh + + var mesh = self.get_node("MeshInstance") as MeshInstance + self.viewport = self.get_node("Viewport") as Viewport + self.label = self.viewport.get_node("MarkdownLabel") as MarkdownLabel + self.shape = mesh.get_node("SignBody/CollisionShape") as CollisionShape + self.quad = mesh.mesh as QuadMesh + + var text_edit = self.viewport.get_node("TextEdit") as TextEdit self.material = mesh.get_active_material(0) as SpatialMaterial text_edit.configure_highlighting @@ -43,26 +69,34 @@ gdobj SignNode of Spatial: proc resize = debug "sign resize", sign = self.model.id + var ratio = self.model.width / self.model.height - size = vec2(viewport.size.x, viewport.size.x / ratio) + size = vec2(viewport_x, viewport_y / ratio) - quad.size = vec2(self.model.width, self.model.height) - shape.scale = vec3(self.model.width, self.model.height, 1) - var t = mesh.transform - t.origin.x = self.model.width / -2 + 0.5 - t.origin.y = self.model.height / -2 + 0.5 - mesh.transform = t - viewport.size = size - label.rect_size = size + self.expanded = false - var stylebox = label.og_label.get_stylebox("normal") as StyleBoxFlat + if self.model.height == 0.0: + self.quad.size = vec2(self.model.width, self.quad.size.y) + self.shape.scale = vec3(self.model.width, self.quad.size.y, 1) + else: + self.quad.size = vec2(self.model.width, self.model.height) + self.shape.scale = vec3(self.model.width, self.model.height, 1) + self.label.rect_size = size + + var t = mesh.transform + t.origin.x = self.model.width / -2 + 0.5 + t.origin.y = self.model.height / -2 + 0.5 + mesh.transform = t + self.viewport.size = size + + var stylebox = self.label.og_label.get_stylebox("normal") as StyleBoxFlat stylebox.content_margin_left = 80 / self.model.width - label.size = int(float(self.model.size) / self.model.width) + self.label.size = int(float(self.model.size) / self.model.width) text_edit.visible = self.model.text_only - label.visible = not self.model.text_only + self.label.visible = not self.model.text_only resize() self.material.params_billboard_mode = @@ -72,32 +106,19 @@ gdobj SignNode of Spatial: BILLBOARD_DISABLED if self.model.text_only: - text_edit.text = self.model.markdown + text_edit.text = self.model.message else: - if self.model.title == "": - label.markdown = self.model.markdown - else: - label.markdown = self.model.title - label.update + self.label.markdown = self.model.message + self.label.update - self.model.title_value.watch: + self.model.message_value.watch: if added or touched: - if change.item == "": - label.markdown = self.model.markdown + if self.model.text_only: + text_edit.text = change.item else: - label.markdown = change.item + self.label.markdown = change.item resize() - label.update - - self.model.markdown_value.watch: - if added or touched: - if self.model.title == "": - if self.model.text_only: - text_edit.text = change.item - else: - label.markdown = change.item - resize() - label.update + self.label.update self.model.glow_value.watch: if added: @@ -124,6 +145,11 @@ gdobj SignNode of Spatial: elif Highlight.removed: self.material.emission_energy = self.model.glow + method physics_process*(delta: float) = + if ?self.model and self.model.height == 0.0 and not self.expanded: + self.expand() + self.expanded = true + method process*(delta: float) = # If we only billboard the material, the collision surface doesn't move # so highlighting the sign is weird from some angles. Align the mesh to the diff --git a/src/types.nim b/src/types.nim index 82766745..02208fa6 100644 --- a/src/types.nim +++ b/src/types.nim @@ -20,11 +20,17 @@ type BlockTargetVisible, ReticleVisible, DocsVisible, MouseCaptured, PrimaryDown, SecondaryDown, EditorFocused, ConsoleFocused, DocsFocused, Playing, Flying, God, - LoadingScript, Server, Quitting + LoadingScript, Server, Quitting, ResettingVM GlobalStateFlags* = enum LoadingWorld + LocalModelFlags* = enum + Hover, TargetMoved, Highlight, Hide + + GlobalModelFlags* = enum + Global, Visible, Lock, Ready, ScriptInitializing, Dirty, Resetting + Tools* = enum CodeMode, BlueBlock, RedBlock, GreenBlock, BlackBlock, WhiteBlock, BrownBlock, PlaceBot @@ -32,11 +38,7 @@ type TaskStates* = enum Running, Done, NextTask - GlobalModelFlags* = enum - Global, Visible, Lock, Ready, ScriptInitializing, Dirty, Resetting - LocalModelFlags* = enum - Hover, TargetMoved, Highlight, Hide ConsoleModel* = ref object log*: ZenSeq[string] @@ -125,10 +127,10 @@ type animation_value*: ZenValue[string] Sign* = ref object of Unit - markdown_value*, title_value*: ZenValue[string] + message_value*, more_value*: ZenValue[string] width_value*, height_value*: ZenValue[float] size_value*: ZenValue[int] - billboard_value*, zoomable_value*: ZenValue[bool] + billboard_value*: ZenValue[bool] owner_value*: ZenValue[Unit] text_only*: bool diff --git a/src/ui/right_panel.nim b/src/ui/right_panel.nim index aac64410..68a7c326 100644 --- a/src/ui/right_panel.nim +++ b/src/ui/right_panel.nim @@ -27,14 +27,14 @@ gdobj RightPanel of MarginContainer: if added and change.item != nil: state.push_flags DocsVisible, DocsFocused var sign = change.item - self.label.markdown = md(sign, sign.markdown) + self.label.markdown = md(sign, sign.more) self.label.update - self.zid = sign.markdown_value.changes: + self.zid = sign.more_value.changes: if added: self.label.markdown = md(sign, change.item) self.label.update if removed and change.item != nil: - change.item.markdown_value.untrack(self.zid) + change.item.more_value.untrack(self.zid) state.pop_flags DocsFocused, DocsVisible state.local_flags.changes: diff --git a/vmlib/enu/base_api.nim b/vmlib/enu/base_api.nim index fc72b27f..c096f066 100644 --- a/vmlib/enu/base_api.nim +++ b/vmlib/enu/base_api.nim @@ -4,6 +4,12 @@ import types, state_machine, base_bridge, base_bridge_private export base_bridge +proc echo*(args: varargs[string, `$`]) = + echo_console(args.join) + +proc quit*(code = 0, msg = "") = + exit(code, msg) + proc `position=`*(self: Unit, position: Vector3) = self.position_set(position) proc `position=`*(self: Unit, unit: Unit) = self.position_set(unit.position) @@ -432,23 +438,6 @@ proc go*(unit: Unit) = proc even*(self: int): bool = self mod 2 == 0 proc odd*(self: int): bool = not self.even -proc md*(self: Unit, - markdown: string, title = "", width = 1.0, height = 1.0, size = 32, - zoomable = true, billboard = false): Sign {.discardable.} = - - result = Sign() - self.new_markdown_sign(result, markdown, title, width, height, size, - zoomable, billboard) - -template md*(markdown: string, - title = "", height = 1.0, width = 1.0, size = 32, zoomable = true, - billboard = false): Sign = - - enu_target.md(markdown, title, width, height, size, zoomable, billboard) - -template reset*(clear = false) = - enu_target.reset(clear) - template `\`*(s: string): string = var f = fmt(s) f.remove_prefix("\n") @@ -464,3 +453,10 @@ template `?`*(self: string): bool = self != "" template `?`*[T](self: open_array[T]): bool = self.len > 0 template `?`*[T](self: set[T]): bool = self.card > 0 template `?`*[T](self: HashSet[T]): bool = self.card > 0 + +proc `or`*[T: not bool](a, b: T): T = + if ?a: result = a + else: result = b + +template reset*(clear = false) = + enu_target.reset(clear) diff --git a/vmlib/enu/base_bridge_private.nim b/vmlib/enu/base_bridge_private.nim index 9090ec6d..ecc48759 100644 --- a/vmlib/enu/base_bridge_private.nim +++ b/vmlib/enu/base_bridge_private.nim @@ -14,6 +14,8 @@ bridged_to_host: proc sleep_impl*(seconds = 1.0) proc position_set*(self: Unit, position: Vector3) - proc new_markdown_sign*(self: Unit, instance: Sign, markdown: string, - title = "", width = 1.0, height = 1.0, size = 32, zoomable = true, - billboard = false) + proc new_markdown_sign*(self: Unit, instance: Sign, message: string, + more = "", width = 1.0, height = 1.0, size = 32, billboard = false) + + proc update_markdown_sign*(self: Sign, message: string, + more = "", width = 1.0, height = 1.0, size = 32, billboard = false) diff --git a/vmlib/enu/class_macros.nim b/vmlib/enu/class_macros.nim index 791c8d12..e8d82c5b 100644 --- a/vmlib/enu/class_macros.nim +++ b/vmlib/enu/class_macros.nim @@ -4,7 +4,7 @@ import base_api, macro_helpers const me_props = ["seed", "global", "lock"] const target_props = ["position", "start_position", "speed", "scale", "glow", - "global", "seed", "color", "height", "show"] + "global", "seed", "color", "height", "show", "sign"] proc params_to_assignments(nodes: seq[NimNode]): NimNode = result = new_stmt_list() diff --git a/vmlib/enu/overrides.nim b/vmlib/enu/overrides.nim deleted file mode 100644 index de98280f..00000000 --- a/vmlib/enu/overrides.nim +++ /dev/null @@ -1,5 +0,0 @@ -proc quit(code = 0, msg = "") = - exit(code, msg) - -proc echo(args: varargs[string, `$`]) = - echo_console(args.join) diff --git a/vmlib/enu/signs.nim b/vmlib/enu/signs.nim index 9ca8f8d3..be761cab 100644 --- a/vmlib/enu/signs.nim +++ b/vmlib/enu/signs.nim @@ -1,12 +1,13 @@ -import std / [strutils, math] -import types, base_api, vm_bridge_utils +import system except echo +import std / [strutils, math, wrapnils, options] +import types, base_api, vm_bridge_utils, base_bridge_private bridged_to_host: - proc markdown*(self: Sign): string = discard - proc `markdown=`*(self: Sign, value: string) = discard + proc message*(self: Sign): string = discard + proc `message=`*(self: Sign, value: string) = discard - proc title*(self: Sign): string = discard - proc `title=`*(self: Sign, value: string) = discard + proc more*(self: Sign): string = discard + proc `more=`*(self: Sign, value: string) = discard proc width*(self: Sign): float = discard proc `width=`*(self: Sign, value: float) = discard @@ -19,3 +20,44 @@ bridged_to_host: proc open*(self: Sign): bool = discard proc `open=`*(self: Sign, value: bool) = discard + + proc billboard*(self: Sign): bool = discard + proc `billboard=`*(self: Sign, value: bool) = discard + +proc say*(self: Unit, message: string, more = "", width = float.high, + height = float.high, size = int.high, billboard = none(bool) + ): Sign {.discardable.} = + + let defaults: tuple[width: float, height: float, size: int, billboard: bool] = + if ?self.sign: + (self.sign.width, self.sign.height, self.sign.size, self.sign.billboard) + elif self of Bot: + (2.0, 0.0, 250, true) + else: + (2.0, 2.0, 250, false) + + let + width = if width == float.high: defaults.width else: width + height = if height == float.high: defaults.height else: height + size = if size == int.high: defaults.size else: size + billboard = billboard.get(defaults.billboard) + + if self of Bot and ?self.sign: + result = self.sign + result.update_markdown_sign(message, more, width, height, size, billboard) + else: + result = Sign() + self.new_markdown_sign(result, message, more, width, height, size, + billboard) + + self.sign = result + + if self of Build and height > 1.0: + result.position = result.position + (UP * (height - 1.0)) + elif self of Bot: + result.position = result.position + (UP * 2) + (LEFT * 1) + result.show = true + +template say*(message: string, more = "", width = float.high, + height = float.high, size = int.high, billboard = none(bool)): Sign = + enu_target.say(message, more, width, height, size, billboard) diff --git a/vmlib/enu/types.nim b/vmlib/enu/types.nim index 56e51618..77601efe 100644 --- a/vmlib/enu/types.nim +++ b/vmlib/enu/types.nim @@ -18,6 +18,7 @@ type advance_state_machine*: proc(): bool rng: Rand seed: int + sign*: Sign PositionOffset* = object position*: Vector3 diff --git a/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim b/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim index 63abb7d3..421adcfd 100644 --- a/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim +++ b/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim @@ -3,11 +3,8 @@ color = white var test_mode = false -var sign = md("# Welcome to Enu!", size = 460, billboard = true) - var bot_id = "" var maze: MazeType -sign.show = false proc get_bot: Bot = # each time the code for the bot is reloaded we need to @@ -19,36 +16,27 @@ proc get_bot: Bot = elif not test_mode and bot.id == bot_id: return bot -proc say(title = "", width = 0.0, height = 0.0, body = "") = - if ?width: sign.width = width - if ?height: sign.height = height - if ?body: sign.markdown = body - if ?title: sign.title = title - sign.show = true - - setup: reset() position = position + LEFT speed = 10 turn player - sign.position = position + (UP * 2.0) + (LEFT * 1.2) - approach: sleep 2 - say "- Hi!", 1.5, 0.5 + say "# - Hi!", width = 1.0 sleep 2 forward 8 turn player sleep 1 - say "- Welcome to **Enu**!", 4.0, 0.6 + say "- Welcome to **Enu**!", width = 2.0 sleep 1.5 - say "- Click this text for a short tutorial.", 3.5, 1.5 - + say "- Click this text for a short tutorial.", "# Welcome to Enu!" while not sign.open: turn(player) - movement_info: - say "...", 0.5, 0.5, """ + say "# . . .", """ # Welcome to Enu! @@ -74,13 +62,13 @@ controller, or by holding down `alt/option (⌥)` on your keyboard. Sneak behind the `Bot` to continue the tutorial. - """ + """, width = 0.6 while me.angle_to(player).abs notin 150..210: sleep 0.5 - flying_info: - say "- Good!", 2.0, 0.5, """ + say "- Good!", """ # Jumping and Flying @@ -96,7 +84,7 @@ ever get yourself stuck you can probably fly your way out. Jump, fly, then returning to the ground to continue the tutorial. - """ + """, width = 1.4 speed = 1 turn player @@ -104,16 +92,16 @@ Jump, fly, then returning to the ground to continue the tutorial. while not player.flying: sleep() - flying_done: - say "- Now drop!", 3.0, 0.5 + say "- Now drop!" while player.flying: sleep() - good_job: sign.open = false - say "- Good Job!", 3.0, 0.5, "# Good Job!" + say "- Good Job!", "# Good Job!" sleep 2 - tool_info: - say "- Switch to `Place Bot`", 3.0, 1.0, """ + say "- Switch to `Place Bot`", """ # Changing tools @@ -131,14 +119,14 @@ friendly robots. Tools `2` - `7` are the `blue`, `red`, `green`, `black`, Select the `Place Bot` tool to continue the tutorial. - """ + """, width = 2.5 sign.open = true while player.tool != PlaceBot: sleep() sleep 0.5 - bot_info: - say "- Place a `Bot`", 3.0, 0.6, """ + say "- Place a `Bot`", """ # Bots @@ -149,13 +137,14 @@ They can be placed with the `left` mouse button or the `R1` gamepad trigger. Place a `Bot` on the ground to continue the tutorial. - """ + """, width = 2.0 sign.open = true var last_bot_frame = frame_count() var og_bot_count = Bot.all.len - while Bot.all.len <= og_bot_count: turn player + while Bot.all.len <= og_bot_count: + turn player for bot in Bot.all: if bot.frame_created > last_bot_frame: last_bot_frame = bot.frame_created @@ -174,7 +163,7 @@ Place a `Bot` on the ground to continue the tutorial. sleep 1 - code_info: - say "- Coding", 2.5, 0.5, """ + say "- Coding", """ # Coding Enu @@ -193,7 +182,7 @@ Switch to the `Code` tool to continue the tutorial. sleep 0.5 - open_code: - say(body = """ + sign.more = """ # Coding Enu @@ -202,7 +191,7 @@ on it with the `left` mouse button, or `R1` on the controller Open the code for your `Bot` to continue the tutorial. - """) + """ sign.open = true var bot = get_bot() @@ -212,7 +201,7 @@ Open the code for your `Bot` to continue the tutorial. sleep 0.5 - bot_navigation: - say(body = """ + sign.more = """ # Coding Bots @@ -248,7 +237,7 @@ turn left Good luck! We'll conclude this tutorial when your `Bot` goes past the `FINISH HERE!` sign at the end of the course. - """) + """ sign.open = true var bot = get_bot() @@ -258,9 +247,9 @@ Good luck! We'll conclude this tutorial when your `Bot` goes past the - win: maze.won = true - say "- Great Job!", 3.0, 0.5, "# Great Job!" + say "- Great Job!", "# Great Job!" sleep 15 - say "- All Done!", 2.5, 0.5, """ + say "- All Done!", """ # Great Job! diff --git a/vmlib/projects/tutorial-1/scripts/build_6spqe6wylsu38.nim b/vmlib/projects/tutorial-1/scripts/build_6spqe6wylsu38.nim index 15db79e1..590ad7eb 100644 --- a/vmlib/projects/tutorial-1/scripts/build_6spqe6wylsu38.nim +++ b/vmlib/projects/tutorial-1/scripts/build_6spqe6wylsu38.nim @@ -2,7 +2,7 @@ name Maze(finished = false, won = false) lock = true proc make_sign: Sign = - md("` `", title="", width=10.0, height=3.0, size=2600, zoomable = false) + say("` `", width = 10.0, height = 3.0, size = 2600) drawing = true if not is_instance: @@ -75,6 +75,8 @@ color = black up 1 turn 180 +color = brown +up 1 var start_sign1 = make_sign() @@ -96,14 +98,14 @@ finished = true proc scroller(sign: Sign, msg: string, pause = 0, len = msg.len): proc() = var current = msg var counter = 0 - + result = proc() = if current == msg and counter < pause: inc counter else: - counter = 0 + counter = 0 current = current[1..^1] & current[0] - sign.title = "`" & current[0..(len - 1)].strip(leading = false) & "`" + sign.message = "`" & current[0..(len - 1)].strip(leading = false) & "`" var start_scroller1 = start_sign1.scroller(" START HERE! ", 0, 7) @@ -119,10 +121,10 @@ forever: end_scroller1() end_scroller2() sleep 0.2 - + if won: break - + drawing = false speed = 0 turn 180 @@ -143,4 +145,3 @@ forever: end_scroller1() end_scroller2() sleep 0.2 - \ No newline at end of file diff --git a/vmlib/projects/tutorial-1/world.json b/vmlib/projects/tutorial-1/world.json index 9798be17..7567757e 100644 --- a/vmlib/projects/tutorial-1/world.json +++ b/vmlib/projects/tutorial-1/world.json @@ -1,4 +1,4 @@ { - "enu_version": "v0.1.99-72-g5e653a17", - "format_version": "v0.9.1" + "enu_version": "v0.1.99-160-g19048be0", + "format_version": "v0.9.2" } \ No newline at end of file