Added `?` operator to convert to bool.

Moved types file to project root.
This commit is contained in:
Scott Wadden 2022-06-27 23:36:09 -03:00
parent c38ac7e72d
commit 2cacc78442
30 changed files with 237 additions and 222 deletions

View File

@ -0,0 +1,11 @@
type
type ScriptController = ref object
retry_failures*: bool
interpreter: Interpreter
module_names: HashSet[string]
active_unit: Unit
unit_map: Table[PNode, Unit]
node_map: Table[Unit, PNode]
failed: seq[tuple[unit: Unit, e: ref VMQuit]]
NodeController* = ref object

View File

@ -1,11 +1,8 @@
import std / [strutils, os, tables]
import pkg / [model_citizen, print]
import pkg / [print]
import pkg/godot except print
import godotapi / [node, spatial]
import models, nodes / [bot_node, build_node, sign_node]
type
NodeController* = ref object
import core, models, nodes / [bot_node, build_node, sign_node]
let state = GameState.active
@ -23,9 +20,9 @@ proc remove_from_scene(unit: Unit) =
if unit of Build: Build(unit).untrack_all
elif unit of Bot: Bot(unit).untrack_all
elif unit of Sign: Sign(unit).untrack_all
if unit.script_ctx:
if ?unit.script_ctx:
unit.script_ctx.callback = nil
if not state.reloading and not unit.clone_of:
if not state.reloading and not ?unit.clone_of:
remove_file unit.script_file
remove_dir unit.data_dir
for child in unit.units:

View File

@ -1,25 +1,21 @@
import std /
import std /
[os, macros, sugar, sets, strutils, times, monotimes, sequtils, importutils,
tables, options, math, re]
import pkg / [print, model_citizen, godot]
import pkg / [print, godot]
import pkg / compiler / vm except get_int
import pkg / compiler / ast except new_node
import pkg / compiler / [vmdef, lineinfos, astalgo, renderer, msgs]
import godotapi / [spatial, ray_cast, voxel_terrain]
import core, models /
[types, states, bots, builds, units, colors, signs, serializers]
import core, models /
[states, bots, builds, units, colors, signs]
import libs / [interpreters, eval]
import nodes / [helpers, build_node]
import nodes / [build_node]
from pkg/compiler/vm {.all.} import stack_trace_aux
type ScriptController* = ref object
interpreter: Interpreter
module_names: HashSet[string]
active_unit: Unit
unit_map: Table[PNode, Unit]
node_map: Table[Unit, PNode]
retry_failures*: bool
failed: seq[tuple[unit: Unit, e: ref VMQuit]]
proc retry_failed_scripts*(self: ScriptController)
import models / serializers
include script_controllers/bindings
@ -30,6 +26,9 @@ const
let state = GameState.active
private_access ScriptController
private_access ScriptCtx
proc map_unit(self: ScriptController, unit: Unit, pnode: PNode) =
self.unit_map[pnode] = unit
self.node_map[unit] = pnode
@ -50,7 +49,6 @@ template info: untyped =
instantiationInfo(-2, fullPaths = true)
proc write_stack_trace(self: ScriptController) =
private_access ScriptCtx
let ctx = self.active_unit.script_ctx
msg_writeln(ctx.ctx.config, "stack trace: (most recent call last)", {msgNoUnitSep})
stack_trace_aux(ctx.ctx, ctx.tos, ctx.pc)
@ -75,7 +73,7 @@ proc get_sign(self: ScriptController, a: VmArgs, pos: int): Sign =
Sign(unit)
proc to_node(self: ScriptController, unit: Unit): PNode =
if unit:
if ?unit:
self.node_map[unit]
else:
ast.new_node(nkNilLit)
@ -136,7 +134,7 @@ proc sleep_impl(ctx: ScriptCtx, seconds: float) =
if seconds > 0 and duration < seconds:
Running
elif seconds <= 0 and duration <= 0.5 and ctx.timer > get_mono_time():
Running
Running
else:
Done
ctx.pause()
@ -331,11 +329,11 @@ proc drop_transform(unit: Unit): Transform =
raise ObjectConversionDefect.init("Unknown unit type")
proc new_markdown_sign_impl(self: ScriptController,
unit: Unit, pnode: PNode, markdown: string, title: string, width: float,
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,
markdown, title = title, owner = self.active_unit,
transform = drop_transform(unit), width = width, height = height,
size = size, zoomable = zoomable, billboard = billboard)
@ -417,33 +415,33 @@ proc `tool=`(self: Unit, value: int) =
state.tool.value = Tools(value)
# Sign bindings
proc title(self: Sign): string =
proc title(self: Sign): string =
self.title.value
proc `title=`(self: Sign, value: string) =
proc `title=`(self: Sign, value: string) =
self.title.value = value
proc markdown(self: Sign): string =
proc markdown(self: Sign): string =
self.markdown.value
proc `markdown=`(self: Sign, value: string) =
proc `markdown=`(self: Sign, value: string) =
self.markdown.value = value
proc width(self: Sign): float =
proc width(self: Sign): float =
self.width
proc `width=`(self: Sign, value: float) =
self.width = value
self.title.touch self.title.value
proc height(self: Sign): float =
proc height(self: Sign): float =
self.height
proc `height=`(self: Sign, value: float) =
self.height = value
self.title.touch self.title.value
proc size(self: Sign): int =
proc size(self: Sign): int =
self.size
proc `size=`(self: Sign, value: int) =
@ -474,7 +472,7 @@ proc script_error(self: ScriptController, unit: Unit, e: ref VMQuit) =
proc advance_unit(self: ScriptController, unit: Unit, delta: float) =
let ctx = unit.script_ctx
if ctx and ctx.running:
if ?ctx and ctx.running:
let now = get_mono_time()
if unit of Build:
@ -487,14 +485,14 @@ proc advance_unit(self: ScriptController, unit: Unit, delta: float) =
while resume_script and not state.paused:
resume_script = false
if ctx.callback == nil or
if ctx.callback == nil or
(task_state = ctx.callback(delta); task_state in {Done, NextTask}):
ctx.timer = MonoTime.high
ctx.action_running = false
self.active_unit = unit
ctx.timeout_at = get_mono_time() + script_timeout
ctx.running = ctx.resume()
if not ctx.running and not unit.clone_of:
if not ctx.running and not ?unit.clone_of:
unit.collect_garbage
unit.ensure_visible
if ctx.running and task_state == NextTask:
@ -536,7 +534,7 @@ proc load_script(self: ScriptController, unit: Unit, timeout = script_timeout) =
if not state.paused:
ctx.timeout_at = get_mono_time() + timeout
ctx.running = ctx.run()
if not ctx.running and not unit.clone_of:
if not ctx.running and not ?unit.clone_of:
unit.collect_garbage
unit.ensure_visible
@ -575,7 +573,7 @@ proc load_script_and_dependants(self: ScriptController, unit: Unit) =
self.retry_failures = true
for other in state.units.value:
if other.script_ctx:
if ?other.script_ctx:
units_by_module[other.script_ctx.module_name] = other
while units_to_reload != previous:
@ -602,7 +600,7 @@ proc load_script_and_dependants(self: ScriptController, unit: Unit) =
state.dirty_units.clear
proc change_code(self: ScriptController, unit: Unit, code: string) =
if unit.script_ctx and unit.script_ctx.running and not unit.clone_of:
if ?unit.script_ctx and unit.script_ctx.running and not ?unit.clone_of:
unit.collect_garbage
var all_edits = unit.shared.edits
@ -645,11 +643,11 @@ proc watch_units(self: ScriptController, units: ZenSeq[Unit]) =
self.watch_code unit
self.watch_units unit.units
if not unit.clone_of and file_exists(unit.script_file):
if not ?unit.clone_of and file_exists(unit.script_file):
unit.code.value = read_file(unit.script_file)
if removed:
self.unmap_unit(unit)
if not unit.clone_of and unit.script_ctx:
if not ?unit.clone_of and ?unit.script_ctx:
self.module_names.excl unit.script_ctx.module_name
proc load_player*(self: ScriptController) =
@ -677,6 +675,7 @@ proc eval*(self: ScriptController, code: string) =
proc init*(T: type ScriptController): ScriptController =
private_access ScriptCtx
private_access ScriptController
let interpreter = Interpreter.init(state.config.script_dir, state.config.lib_dir)
interpreter.config.spell_suggest_max = 0
@ -699,9 +698,9 @@ proc init*(T: type ScriptController): ScriptController =
raise (ref VMQuit)(info: info, msg: msg, location: loc)
interpreter.register_enter_hook proc(c, pc, tos, instr: auto) =
assert controller
assert controller.active_unit
assert controller.active_unit.script_ctx
assert ?controller
assert ?controller.active_unit
assert ?controller.active_unit.script_ctx
let ctx = controller.active_unit.script_ctx
let info = c.debug[pc]
@ -731,15 +730,15 @@ proc init*(T: type ScriptController): ScriptController =
result.watch_units state.units
result.bind_procs "base_bridge",
register_active, echo_console, new_instance, exec_instance, hit, exit,
global, `global=`, position, local_position, rotation, `rotation=`, id,
glow, `glow=`, speed, `speed=`, scale, `scale=`, velocity, `velocity=`,
active_unit, color, `color=`, seen, start_position, wake, frame_count,
register_active, echo_console, new_instance, exec_instance, hit, exit,
global, `global=`, position, local_position, rotation, `rotation=`, id,
glow, `glow=`, speed, `speed=`, scale, `scale=`, velocity, `velocity=`,
active_unit, color, `color=`, seen, start_position, wake, frame_count,
write_stack_trace, show, `show=`, frame_created, lock, `lock=`, reset,
press_action
result.bind_procs "base_bridge_private",
link_dependency_impl, action_running, `action_running=`, yield_script,
link_dependency_impl, action_running, `action_running=`, yield_script,
begin_turn, begin_move, sleep_impl, `position=impl`, new_markdown_sign_impl
result.bind_procs "bots",

View File

@ -1,3 +1,6 @@
import types
export types
const enu_version* = static_exec("git describe --tags HEAD")
### Sugar ###
@ -62,15 +65,15 @@ proc `+`*(time: MonoTime, interval: TimeInterval): MonoTime =
proc `-`*(time: MonoTime, interval: TimeInterval): MonoTime =
time - interval.to_duration
### ref ###
converter to_bool*(self: ref): bool = not self.is_nil
### options ###
import options
export options
# converter to_option*[T](val: T): Option[T] =
# some(val)
proc `?`*(self: ref): bool = not self.is_nil
proc `?`*[T](option: Option[T]): bool = option.is_some
proc `?`*(self: SomeNumber): bool = self > 0
proc `?`*(self: string): bool = self != ""
proc `?`*[T](self: open_array[T]): bool = self.len > 0
proc `||=`*[T](opt: var Option[T], val: T): T {.discardable.} =
if not opt.is_some:
@ -82,9 +85,6 @@ proc `||=`*[T](opt: var Option[T], val: T): T {.discardable.} =
converter from_option*[T](val: Option[T]): T =
val.get()
converter to_bool*[T](option: Option[T]): bool =
option.is_some
proc optional_get*[T](self: var HashSet[T], key: T): Option[T] =
if key in self:
result = some(self[key])
@ -185,3 +185,47 @@ when true: # do something here for tests. Godot print crashes without godot.
proc p*(args: varargs[string, `$`]) =
let msg = args.join
godot.print msg
# misc
import pkg / core / transforms
export transforms
import godotapi / [spatial]
import pkg / model_citizen
export model_citizen except `%`
proc local_to*(self: Vector3, unit: Unit): Vector3 =
result = self
var unit = unit
while unit != nil:
result -= unit.node.transform.origin
unit = unit.parent
proc global_from*(self: Vector3, unit: Unit): Vector3 =
result = -self.local_to(unit)
proc init*(_: type Transform, origin = vec3()): Transform =
result = init_transform()
result.origin = origin
proc `+=`*(self: ZenValue[string], str: string) =
self.value = self.value & str
proc origin*(self: ZenValue[Transform]): Vector3 =
self.value.origin
proc `origin=`*(self: ZenValue[Transform], value: Vector3) =
var transform = self.value
transform.origin = value
self.value = transform
proc basis*(self: ZenValue[Transform]): Basis =
self.value.basis
proc `basis=`*(self: ZenValue[Transform], value: Basis) =
var transform = self.value
transform.basis = value
self.value = transform
proc init*(_: type Basis): Basis = init_basis()

View File

@ -1,11 +1,11 @@
import std / [monotimes, times, os, jsonutils, json, math]
import pkg / [godot, model_citizen, zippy / ziparchives]
import pkg / [godot, zippy / ziparchives]
import godotapi / [input, input_event, gd_os, node, scene_tree,
packed_scene, sprite, control, viewport, viewport_texture,
performance, label, theme, dynamic_font, resource_loader, main_loop,
project_settings, input_map, input_event_action, input_event_key, global_constants,
scroll_container]
import core, globals, controllers / [node_controllers, script_controllers], models / serializers
import core, types, globals, controllers / [node_controllers, script_controllers], models / serializers
type
UserConfig = object
@ -282,12 +282,12 @@ gdobj Game of Node:
if event.is_action_pressed("previous"):
self.prev_action()
# NOTE: alt+enter isn't being picked up on windows if the editor is open. Needs investigation.
if event.is_action_pressed("toggle_fullscreen") or (host_os == "windows" and
CommandMode in state.flags and EditorVisible in state.flags and
if event.is_action_pressed("toggle_fullscreen") or (host_os == "windows" and
CommandMode in state.flags and EditorVisible in state.flags and
event of InputEventKey and event.as(InputEventKey).scancode == KEY_ENTER):
set_window_fullscreen not is_window_fullscreen()
elif event.is_action_pressed("next_world"):
elif event.is_action_pressed("next_world"):
self.switch_world(+1)
elif event.is_action_pressed("prev_world"):
self.switch_world(-1)

View File

@ -1,7 +1,7 @@
import std / [strformat, tables]
import pkg / [godot, model_citizen]
import pkg / [godot]
import godotapi / [node, scene_tree, voxel_buffer]
import core, models / [states, types]
import core, models / [states]
export strformat.`&`, states, types
type

View File

@ -3,7 +3,6 @@ import pkg / compiler / ast except new_node
import pkg / godot except print
import pkg / [print], pkg / compiler / [vm, vmdef, options, lineinfos, llstream]
import core, eval
import models/types
export Interpreter, VmArgs, set_result
@ -30,12 +29,14 @@ proc load*(self: ScriptCtx, file_name, code: string) =
self.file_name = file_name
proc run*(self: ScriptCtx): bool =
private_access ScriptCtx
self.exit_code = none(int)
self.errors = @[]
try:
self.interpreter.load_module(self.file_name, self.code, self.pass_context)
result = false
except VMPause:
private_access ScriptCtx
result = self.exit_code.is_none
except:
self.running = false

View File

@ -1,5 +0,0 @@
import pkg / core / [transforms, godotcoretypes]
export transforms except `==`
proc `==`*(self: Transform; b: Transform): bool {.inline.} =
self.origin == b.origin and self.basis == b.basis

View File

@ -1,6 +1,4 @@
import pkg / [model_citizen]
import models / [types, states, units, builds, bots, ground, colors, players,
import models / [states, units, builds, bots, ground, colors, players,
signs]
export model_citizen except `%`
export types, states, units, builds, bots, ground, colors, players, signs
export states, units, builds, bots, ground, colors, players, signs

View File

@ -1,7 +1,6 @@
import std / [math, sugar, monotimes]
import pkg / model_citizen
import godotapi / spatial
import core, models / [types, states, units, colors]
import core, models / [states, units, colors]
include "bot_code_template.nim.nimf"
let state = GameState.active
@ -75,13 +74,13 @@ proc init*(_: type Bot, id = "bot_" & generate_id(), transform = Transform.init,
scale: Zen.init(1.0),
color: Zen.init(action_colors[black]),
start_color: action_colors[black],
shared: if parent: parent.shared else: Shared(),
shared: if ?parent: parent.shared else: Shared(),
parent: parent,
frame_created: state.frame_count
)
if clone_of == nil:
state.dirty_units.incl self
if global: self.flags += Global
self.flags += Visible
@ -96,7 +95,7 @@ proc init*(_: type Bot, id = "bot_" & generate_id(), transform = Transform.init,
root.walk_tree proc(unit: Unit) = unit.flags -= Highlight
state.pop_flag ReticleVisible
self.state_zids.add:
self.state_zids.add:
state.flags.changes:
if Hover in self.flags:
if PrimaryDown.added and state.tool.value == CodeMode:

View File

@ -1,7 +1,7 @@
import std / [hashes, tables, sets, options, sequtils, math, wrapnils, monotimes, sugar, deques]
import pkg / [model_citizen, print]
import pkg / [print]
import godotapi / spatial
import core, models / [types, states, bots, colors, units]
import core, models / [states, bots, colors, units]
const ChunkSize = vec3(16, 16, 16)
include "build_code_template.nim.nimf"
@ -50,7 +50,7 @@ proc find_first*(units: ZenSeq[Unit], positions: open_array[Vector3]): Build =
if info.kind != Hole and info.color != action_colors[eraser]:
return unit
let first = unit.units.find_first(positions)
if first:
if ?first:
return first
proc add_build(self, source: Build) =
@ -72,7 +72,7 @@ proc maybe_join_previous_build(self: Build, position: Vector3, voxel: VoxelInfo)
previous_build = current_build
current_build = self
if previous_build and previous_build != self:
if ?previous_build and previous_build != self:
var partner = previous_build
let root = previous_build.find_root
if root of Build:
@ -89,7 +89,7 @@ proc maybe_join_previous_build(self: Build, position: Vector3, voxel: VoxelInfo)
source = self
dest = partner
if source and dest:
if ?source and ?dest:
dest.add_build(source)
current_build = dest
return
@ -147,7 +147,7 @@ proc draw*(self: Build, position: Vector3, voxel: VoxelInfo) =
return
elif edit.kind == Manual and edit.color == voxel.color:
self.shared.edits[self.id].del position
elif self.clone_of and position in self.clone_of.shared.edits[self.clone_of.id] and
elif ?self.clone_of and position in self.clone_of.shared.edits[self.clone_of.id] and
self.clone_of.shared.edits[self.clone_of.id][position].kind == Hole:
return
else:
@ -201,7 +201,7 @@ proc fire(self: Build) =
skip_point = self.target_point + self.target_normal
last_point = self.target_point
self.draw(point, (Manual, state.selected_color))
elif state.tool.value == PlaceBot and EditorVisible in state.flags and
elif state.tool.value == PlaceBot and EditorVisible in state.flags and
state.bot_at(global_point).is_nil:
let transform = Transform.init(origin = global_point)
@ -238,7 +238,7 @@ method on_begin_move*(self: Build, direction: Vector3, steps: float, move_mode:
self.voxels_remaining_this_frame = self.speed
self.voxels_per_frame = self.speed
var count = 0
result = proc(delta: float): TaskStates =
while count.float < steps and self.voxels_remaining_this_frame >= 1 and
get_mono_time() < state.timeout_frame_at:
@ -340,10 +340,10 @@ proc init*(_: type Build, id = "build_" & generate_id(), transform = Transform.i
bot_collisions: bot_collisions,
frame_delta: ZenValue[float].init,
scale: Zen.init(1.0),
shared: if parent: parent.shared else: Shared(),
shared: if ?parent: parent.shared else: Shared(),
frame_created: state.frame_count
)
if clone_of == nil:
state.dirty_units.incl self
@ -361,12 +361,12 @@ proc init*(_: type Build, id = "build_" & generate_id(), transform = Transform.i
let root = self.find_root(true)
root.walk_tree proc(unit: Unit) = unit.flags -= Highlight
if TargetMoved.touched:
let length = (self.target_point * self.target_normal - last_point * self.target_normal).length
let length = (self.target_point * self.target_normal - last_point * self.target_normal).length
if state.skip_block_paint:
state.skip_block_paint = false
elif state.draw_unit_id == self.id and self.target_normal == draw_normal and
length <= 5 and self.target_point != skip_point:
if SecondaryDown in state.flags:
self.remove
elif PrimaryDown in state.flags:
@ -395,7 +395,7 @@ proc init*(_: type Build, id = "build_" & generate_id(), transform = Transform.i
method on_collision*(self: Build, partner: Model, normal: Vector3) =
self.collisions.add (partner, normal)
if self.script_ctx:
if ?self.script_ctx:
self.script_ctx.timer = get_mono_time()
method off_collision*(self: Build, partner: Model) =
@ -404,7 +404,7 @@ method off_collision*(self: Build, partner: Model) =
if collision.model != partner:
collision
if self.script_ctx:
if ?self.script_ctx:
self.script_ctx.timer = get_mono_time()
method clone*(self: Build, clone_to: Unit, id: string): Unit =
@ -414,7 +414,7 @@ method clone*(self: Build, clone_to: Unit, id: string): Unit =
transform = Build(clone_to).draw_transform
global = false
# we need this off for Potato Zombies, but on for the
# we need this off for Potato Zombies, but on for the
# tutorials. Make it configurable somehow.
let bot_collisions = true #not (clone_to of Bot)
let clone = Build.init(id = id, transform = transform, clone_of = self, global = global, parent = clone_to,

View File

@ -1,7 +1,7 @@
import std / [sugar]
import pkg / [model_citizen, print]
import pkg / [print]
import godotapi / spatial
import core, types, states, bots, builds
import core, states, bots, builds
let state = GameState.active
@ -12,7 +12,7 @@ proc fire(self: Ground, append = false) =
if state.tool.value notin {CodeMode, PlaceBot}:
if not append:
add_to = state.units.find_first(point.surrounding)
if add_to:
if ?add_to:
let local = point.local_to(add_to)
add_to.draw(local, (Manual, state.selected_color))
else:

View File

@ -1,7 +1,5 @@
import std / math
import pkg / model_citizen
import godotapi / spatial
import models / [types]
import core
proc init*(_: type Player, node: Spatial): Player =

View File

@ -1,10 +1,8 @@
import system except write_file
import std / [json, jsonutils, sugar, tables, strutils, os]
import pkg / print
proc save_world*()
import core, models, controllers / script_controllers
import core, models
import controllers / script_controllers
let state = GameState.active
var load_chunks = false
@ -115,8 +113,8 @@ proc from_json_hook(self: var Bot, json: JsonNode) =
self.shared.edits.from_json(json["edits"])
proc save*(unit: Unit) =
if not unit.clone_of:
let data =
if not ?unit.clone_of:
let data =
if unit of Build:
Build(unit).to_json.pretty
elif unit of Bot:
@ -139,10 +137,11 @@ proc save_world*() =
proc load_units(parent: Unit) =
let opts = JOptions(allow_missing_keys: true)
let path = if parent:
parent.data_dir
else:
state.config.data_dir
let path =
if ?parent:
parent.data_dir
else:
state.config.data_dir
for dir in walk_dirs(path / "*"):
let unit_id = dir.split_path.tail
let data_file = read_file(dir / unit_id & ".json").parse_json

View File

@ -1,13 +1,13 @@
import std / [sugar]
import pkg / [model_citizen, print]
import pkg / [print]
import godotapi / spatial
import core, types, states, bots, builds, models / colors
import core, states, bots, builds, models / colors
let state = GameState.active
proc init*(_: type Sign,
markdown: string, title = "", owner: Unit, transform = Transform.init,
width = 1.0, height = 1.0, size = 32, billboard = false,
proc init*(_: type Sign,
markdown: string, title = "", owner: Unit, transform = Transform.init,
width = 1.0, height = 1.0, size = 32, billboard = false,
zoomable = true): Sign =
let title = if title == "": markdown else: title

View File

@ -1,6 +1,6 @@
import std / [tables, strutils, sequtils, algorithm, sets, sugar]
import pkg / [model_citizen, print]
import models / [types, colors]
import pkg / [print]
import core, models / [colors]
# only one flag from the group is active at a time
const groups = @[
@ -25,7 +25,7 @@ proc resolve_flags(self: GameState) =
if not groups[1].any_it(it in result):
result.incl ReticleVisible
if CommandMode in result:
result.incl(MouseCaptured)
for flag in groups[0]:
@ -36,7 +36,7 @@ proc resolve_flags(self: GameState) =
if MouseCaptured notin result:
result.excl(ReticleVisible)
self.flags.value = result
proc replace_flags*(self: GameState, flags: varargs[StateFlags]) =
@ -55,7 +55,7 @@ proc push_flags*(self: GameState, flags: varargs[StateFlags]) =
for flag in flags:
self.wants.incl flag
self.resolve_flags
proc push_flag*(self: GameState, flag: StateFlags) =
self.push_flags flag
@ -74,10 +74,10 @@ proc set_flag*(self: GameState, flag: StateFlags, value: bool) =
else:
self.pop_flag flag
proc `+=`*(self: ZenSet[StateFlags], flag: StateFlags) {.error:
proc `+=`*(self: ZenSet[StateFlags], flag: StateFlags) {.error:
"Use `push_flag`, `pop_flag` and `replace_flag`".}
proc `-=`*(self: ZenSet[StateFlags], flag: StateFlags) {.error:
proc `-=`*(self: ZenSet[StateFlags], flag: StateFlags) {.error:
"Use `push_flag`, `pop_flag` and `replace_flag`".}
proc selected_color*(self: GameState): Color =

View File

@ -1,8 +1,7 @@
import std / [os, sugar]
import pkg / model_citizen
import godotapi / spatial
from pkg/core/godotcoretypes import Basis
import core, models / [types, states, colors], libs / interpreters
import core, models / [states, colors], libs / interpreters
proc find_root*(self: Unit, all_clones = false): Unit =
result = self
@ -11,7 +10,7 @@ proc find_root*(self: Unit, all_clones = false): Unit =
while parent != nil:
result = parent
if (all_clones and not parent.clone_of) or (not all_clones and Global in parent.flags):
if (all_clones and not ?parent.clone_of) or (not all_clones and Global in parent.flags):
parent = nil
else:
parent = parent.parent

View File

@ -1,5 +1,5 @@
import std / [strutils, wrapnils]
import pkg / [godot, model_citizen]
import pkg / [godot]
import godotapi / [sprite_3d, ray_cast, spatial]
import globals, core, nodes/helpers, models
@ -40,7 +40,7 @@ gdobj AimTarget of Sprite3D:
self.target_model.flags -= Hover
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 not Sign(unit).zoomable) or
(God notin state.flags and (unit of Bot or unit of Build) and
Lock in Unit(unit).find_root.flags)):
@ -73,7 +73,7 @@ gdobj AimTarget of Sprite3D:
let align_normal = self.transform.origin + global_normal
self.look_at(align_normal, self.transform.basis.x)
if unit:
if ?unit:
if (unit.target_point, unit.target_normal) != (local_point, local_normal):
unit.target_point = local_point
unit.target_normal = local_normal

View File

@ -1,11 +1,11 @@
import std / [tables, sugar, os, math]
import pkg/godot except print
import pkg / [model_citizen, chroma]
import pkg / [chroma]
import godotapi / [scene_tree, kinematic_body, material, mesh_instance, spatial,
input_event, animation_player, resource_loader, packed_scene,
spatial_material]
import globals, core, print
import models / [types, bots, units, states, colors]
import core, models / [bots, units, states, colors]
let state = GameState.active
@ -43,10 +43,10 @@ gdobj BotNode of KinematicBody:
adjusted = color
adjusted.a = 0.1
else:
var dist = (color.distance(action_colors[brown]) + 10).cbrt / 7.5
var dist = (color.distance(action_colors[brown]) + 10).cbrt / 7.5
adjusted = color.saturate(0.2).darken(dist - 0.15)
adjusted.a = 0.95 - color.distance(action_colors[black]) / 100
SpatialMaterial(self.material).albedo_color = adjusted
proc set_visibility =
@ -76,7 +76,7 @@ gdobj BotNode of KinematicBody:
self.set_default_material()
elif change.item == Visible:
self.set_visibility
self.model.state_zids.add:
state.flags.changes:
if change.item == God:
@ -124,7 +124,7 @@ gdobj BotNode of KinematicBody:
self.track_changes
method process(delta: float) =
if self.model:
if ?self.model:
self.model.frame_delta.touch delta
self.model.transform.pause self.transform_zid:
self.model.transform.value = self.transform

View File

@ -1,9 +1,9 @@
import std / [tables, bitops]
import pkg/godot except print, Color
import pkg / [print, model_citizen]
import pkg / [print]
import godotapi / [node, voxel_terrain, voxel_mesher_blocky, voxel_tool, voxel_library, shader_material,
resource_loader, packed_scene]
import models / [types, builds, colors, units, states], globals
import core, models / [builds, colors, units, states], globals
const
highlight_glow = 1.0
@ -140,7 +140,7 @@ gdobj BuildNode of VoxelTerrain:
self.transform = change.item
method process(delta: float) =
if self.model:
if ?self.model:
self.model.frame_delta.touch delta
self.model.transform.pause self.transform_zid:
self.model.transform.value = self.transform

View File

@ -1,6 +1,6 @@
import pkg/godot
import godotapi/node
import models/types, bot_node, build_node, ground_node, selection_area, sign_node
import core, bot_node, build_node, ground_node, selection_area, sign_node
proc model*(self: Object): Model =
result = if self of SelectionArea:

View File

@ -1,6 +1,5 @@
import std / [math, sugar]
import pkg / godot except print
import pkg / model_citizen
import godotapi / [kinematic_body, spatial, input, input_event,
input_event_mouse_motion, input_event_joypad_motion,
ray_cast, scene_tree, input_event_pan_gesture, viewport, camera, global_constants,
@ -86,7 +85,7 @@ gdobj PlayerNode of KinematicBody:
var speed = vec3(move_speed)
if running: speed *= vec3(2)
if flying: speed *= vec3(3, 2, 3)
result = move_direction * delta * speed
if result.length() > max_speed:
result = result.normalized() * max_speed
@ -96,7 +95,7 @@ gdobj PlayerNode of KinematicBody:
float_time + float_time
else:
float_time
let floating = self.jump_down and self.jump_time and self.jump_time.get + float_time > now()
let floating = self.jump_down and ?self.jump_time and self.jump_time.get + float_time > now()
let gravity = if floating:
state.gravity / 4
else:
@ -159,7 +158,7 @@ gdobj PlayerNode of KinematicBody:
self.camera_rig.rotation = r
self.unit.rotation.pause(self.rotation_zid):
self.unit.rotation.value = rad_to_deg r.y
let ray_length = if state.tool.value == CodeMode: 200.0 else: 100.0
if MouseCaptured notin state.flags:
let
@ -181,8 +180,8 @@ gdobj PlayerNode of KinematicBody:
state.pop_flag CommandMode
const forward_rotation = deg_to_rad(-90.0)
let
process_input =
let
process_input =
EditorVisible notin state.flags or CommandMode in state.flags
input_direction = if process_input: self.get_input_direction()
else: vec3()
@ -250,7 +249,7 @@ gdobj PlayerNode of KinematicBody:
self.input_relative += event.as(InputEventMouseMotion).relative()
else:
self.skip_next_mouse_move = false
if EditorVisible in state.flags and not self.skip_release and
if EditorVisible in state.flags and not self.skip_release and
(event of InputEventJoypadButton or event of InputEventJoypadMotion):
let active_input = self.has_active_input(event.device.int)
@ -266,7 +265,7 @@ gdobj PlayerNode of KinematicBody:
self.jump_down = true
let
time = now()
toggle = self.jump_time and time < self.jump_time.get + fly_toggle
toggle = ?self.jump_time and time < self.jump_time.get + fly_toggle
if toggle:
self.jump_time = nil_time
@ -287,7 +286,7 @@ gdobj PlayerNode of KinematicBody:
if event.is_action_pressed("run"):
let
time = now()
toggle = self.run_time and time < self.run_time.get + run_toggle
toggle = ?self.run_time and time < self.run_time.get + run_toggle
if toggle:
self.run_time = nil_time

View File

@ -1,4 +1,4 @@
import pkg / [godot, model_citizen]
import pkg / [godot]
import godotapi / [area, control]
import core, globals, nodes/bot_node

View File

@ -1,8 +1,8 @@
import pkg / [godot, model_citizen]
import pkg / [godot]
import godotapi / [spatial, resource_loader, packed_scene, collision_shape,
mesh_instance, quad_mesh, spatial_material, viewport,
style_box_flat]
import ui / markdown_label, models / [types, signs]
import ui / markdown_label, models / [signs]
import core, models / [states]
let state = GameState.active
@ -35,7 +35,7 @@ gdobj SignNode of Spatial:
var
ratio = self.model.width / self.model.height
size = vec2(viewport.size.x, viewport.size.x / ratio)
quad.size = vec2(self.model.width, self.model.height)
shape.scale = vec3(self.model.width, self.model.height, 1)
var t = mesh.transform
@ -68,7 +68,7 @@ gdobj SignNode of Spatial:
label.markdown = change.item
resize()
label.update
self.model.markdown.changes:
if added or touched:
if self.model.title.value == "":
@ -89,8 +89,8 @@ gdobj SignNode of Spatial:
if change.item == Visible:
self.set_visibility
self.model.state_zids.add:
self.model.state_zids.add:
state.flags.changes:
if God.removed:
self.set_visibility

View File

@ -1,12 +1,13 @@
import std / [tables, monotimes, sets]
import std / [tables, monotimes, sets, options]
import godotapi / [spatial, ray_cast]
import pkg/model_citizen
import pkg/core/godotcoretypes except Color
import pkg / core / [vector3, basis, aabb, godotbase]
import pkg / compiler / passes {.all.}
import core, models/colors, libs / [transforms, eval]
import pkg / compiler / ast
import pkg / model_citizen
import models/colors, libs / [eval]
export Vector3, Transform, vector3, transforms, basis, AABB, aabb
export Vector3, Transform, vector3, basis, AABB, aabb
export godotbase except print
export Interpreter
@ -14,7 +15,7 @@ type
StateFlags* = enum
CommandMode, EditorVisible, ConsoleVisible,
BlockTargetVisible, ReticleVisible, DocsVisible, MouseCaptured,
BlockTargetVisible, ReticleVisible, DocsVisible, MouseCaptured,
PrimaryDown, SecondaryDown, EditorFocused, ConsoleFocused, DocsFocused,
Playing, Flying, God
@ -179,38 +180,13 @@ type
Callback* = proc(delta: float): TaskStates
# TODO: this shouldn't be here
proc local_to*(self: Vector3, unit: Unit): Vector3 =
result = self
var unit = unit
while unit:
result -= unit.node.transform.origin
unit = unit.parent
ScriptController* = ref object
retry_failures*: bool
interpreter: Interpreter
module_names: HashSet[string]
active_unit: Unit
unit_map: Table[PNode, Unit]
node_map: Table[Unit, PNode]
failed: seq[tuple[unit: Unit, e: ref VMQuit]]
proc global_from*(self: Vector3, unit: Unit): Vector3 =
result = -self.local_to(unit)
proc init*(_: type Transform, origin = vec3()): Transform =
result = init_transform()
result.origin = origin
proc `+=`*(self: ZenValue[string], str: string) =
self.value = self.value & str
proc origin*(self: ZenValue[Transform]): Vector3 =
self.value.origin
proc `origin=`*(self: ZenValue[Transform], value: Vector3) =
var transform = self.value
transform.origin = value
self.value = transform
proc basis*(self: ZenValue[Transform]): Basis =
self.value.basis
proc `basis=`*(self: ZenValue[Transform], value: Basis) =
var transform = self.value
transform.basis = value
self.value = transform
proc init*(_: type Basis): Basis = init_basis()
NodeController* = ref object

View File

@ -1,6 +1,6 @@
import godotapi / [text_edit, scene_tree, node, input_event, input_event_key,
rich_text_label, global_constants]
import godot, model_citizen
import godot
import std / strutils
import globals, core

View File

@ -1,5 +1,5 @@
import std / [strutils, tables]
import pkg / [godot, model_citizen]
import pkg / [godot]
import pkg / compiler / [lineinfos]
import godotapi / [text_edit, scene_tree, node, input_event, global_constants,
input_event_key, style_box_flat, gd_os]
@ -18,15 +18,15 @@ gdobj Editor of TextEdit:
proc set_open_script_ctx() =
# TODO: yuck
var current = self.open_script_ctx
if not state.open_unit.value.is_nil and state.open_unit.value.script_ctx:
if ?state.open_unit.value and ?state.open_unit.value.script_ctx:
current = state.open_unit.value.script_ctx
if self.open_script_ctx != current:
if self.open_script_ctx:
if ?self.open_script_ctx:
self.open_script_ctx.line_changed = nil
if not state.open_unit.value.is_nil and not state.open_unit.value.script_ctx.is_nil:
self.open_script_ctx = state.open_unit.value.script_ctx
if self.open_script_ctx:
if ?self.open_script_ctx:
self.executing_line = int self.open_script_ctx.current_line.line - 1
self.open_script_ctx.line_changed = proc(current: TLineInfo, previous: TLineInfo) =
self.executing_line = int current.line - 1
@ -114,7 +114,7 @@ gdobj Editor of TextEdit:
if unit.is_nil:
self.release_focus()
self.visible = false
if self.open_script_ctx:
if ?self.open_script_ctx:
self.open_script_ctx.line_changed = nil
self.open_script_ctx = nil
else:
@ -137,7 +137,7 @@ gdobj Editor of TextEdit:
state.open_unit.value.code.value = self.text
self.modulate = dimmed_alpha
self.release_focus
elif CommandMode.removed:
if EditorVisible in state.flags:
self.modulate = solid_alpha

View File

@ -1,5 +1,5 @@
import std / [lists, algorithm, tables]
import pkg / [godot, markdown, hmatching, print, model_citizen]
import pkg / [godot, markdown, hmatching, print]
import godotapi / [rich_text_label, scroll_container, text_edit, theme,
dynamic_font, dynamic_font_data, style_box_flat, main_loop]
import core, globals
@ -9,7 +9,7 @@ export scroll_container
const comment_color = col"808080"
proc stylebox(self: Control): StyleBoxFlat =
proc stylebox(self: Control): StyleBoxFlat =
self.get_stylebox("normal").as(StyleBoxFlat)
gdobj MarkdownLabel of ScrollContainer:
@ -46,7 +46,7 @@ gdobj MarkdownLabel of ScrollContainer:
GameState.active.nodes.game.bind_signals(self.current_label, "meta_clicked")
proc set_font_sizes =
var size =
var size =
if self.size > 0:
self.size
else:
@ -56,7 +56,7 @@ gdobj MarkdownLabel of ScrollContainer:
self.local_italic_font.size = size
self.local_bold_font.size = size
self.local_bold_italic_font.size = size
self.local_mono_font.size = size
self.local_mono_font.size = size
self.local_header_font.size = size * 2
for i, child in self.container.get_children:
@ -66,11 +66,11 @@ gdobj MarkdownLabel of ScrollContainer:
var child = TextEdit(child)
var height = child.get_line_count * child.get_line_height + 24
let lines = dup child.text.split_lines.sorted_by_it(it.len)
var size = child.rect_min_size
size.y = float height
if lines.len > 0:
let str_size =
let str_size =
self.local_mono_font.get_string_size(" ".repeat(lines.len + 2))
size.x = str_size.x
child.rect_min_size = size
@ -78,7 +78,7 @@ gdobj MarkdownLabel of ScrollContainer:
elif child of RichTextLabel:
var stylebox = self.current_label.stylebox
stylebox.content_margin_bottom = 0
if i > 0:
stylebox.content_margin_top = float(size + 4)
if i == self.container.get_children.len - 1:
@ -113,7 +113,7 @@ gdobj MarkdownLabel of ScrollContainer:
self.og_text_edit.add_font_override("font", self.local_mono_font)
self.og_label.add_font_override("normal_font", self.local_default_font)
self.zid = GameState.active.config.font_size.changes:
if added:
self.set_font_sizes()
@ -124,7 +124,7 @@ gdobj MarkdownLabel of ScrollContainer:
if not self.resized:
self.set_font_sizes()
self.resized = true
proc render_markdown(token: Token, list_position = 0, inline_blocks = false) =
var list_position = list_position
for t in token.children:
@ -132,11 +132,11 @@ gdobj MarkdownLabel of ScrollContainer:
if self.needs_margin and not (t of CodeBlock):
label.newline
self.needs_margin = false
case t:
of of Heading():
label.with(push_font self.local_header_font,
push_color ir_black[keyword])
label.with(push_font self.local_header_font,
push_color ir_black[keyword])
self.render_markdown t
label.with(pop, pop, newline)
self.needs_margin = true
@ -150,7 +150,7 @@ gdobj MarkdownLabel of ScrollContainer:
label.push_font self.local_bold_font
self.render_markdown t
label.pop
of of CodeSpan():
label.with(push_font self.local_mono_font, push_color ir_black[number],
add_text t.doc)
@ -159,13 +159,13 @@ gdobj MarkdownLabel of ScrollContainer:
of of CodeBlock():
self.needs_margin = false
var editor = self.add_text_edit()
editor.text = t.doc[0..^2]
editor.visible = true
self.container.add_child editor
self.add_label()
of of Paragraph():
self.render_markdown(t, inline_blocks = inline_blocks)
if not inline_blocks:

View File

@ -1,7 +1,7 @@
import pkg / [godot, model_citizen]
import pkg / [godot]
import godotapi / [margin_container, input_event, scene_tree]
import ui / markdown_label
import models / [types, states, colors]
import core, models / [states, colors]
let state = GameState.active
@ -19,7 +19,7 @@ gdobj RightPanel of MarginContainer:
method ready* =
self.label = self.find_node("MarkdownLabel") as MarkdownLabel
state.open_sign.changes:
if added and change.item != nil:
state.push_flags DocsVisible, DocsFocused
@ -33,7 +33,7 @@ gdobj RightPanel of MarginContainer:
if removed and change.item != nil:
change.item.markdown.untrack(self.zid)
state.pop_flags DocsFocused, DocsVisible
state.flags.changes:
if DocsVisible.added:
self.label.visible = true
@ -45,12 +45,12 @@ gdobj RightPanel of MarginContainer:
self.modulate = dimmed_alpha
elif CommandMode.removed:
self.modulate = solid_alpha
method unhandled_input*(event: InputEvent) =
if DocsFocused in state.flags and event.is_action_pressed("ui_cancel"):
if not (event of InputEventJoypadButton) or CommandMode notin state.flags:
state.open_sign.value = nil
self.get_tree().set_input_as_handled()

View File

@ -1,7 +1,7 @@
import godotapi / [h_box_container, scene_tree, button, image_texture]
import pkg / [godot, model_citizen]
import models / [types, states]
import ".." / [core, globals, game, ui/preview_maker]
import pkg / [godot]
import core, models / [states]
import globals, ui/preview_maker
type
PreviewResult = tuple[color: string, preview: Image]