250 lines
6.9 KiB
GDScript
250 lines
6.9 KiB
GDScript
extends Node
|
|
|
|
# class member variables go here, for example:
|
|
# var a = 2
|
|
# var b = "textvar"
|
|
|
|
|
|
var command_registry = Dictionary();
|
|
var command_history = []
|
|
|
|
export(bool) var debug = false
|
|
|
|
export(NodePath) var level_path = 'res://levels/sample/level.tscn'
|
|
var level = null
|
|
|
|
export(float) var turn_max_length = 60.0 # Seconds
|
|
var turn_time_left = -1.0
|
|
|
|
export(int) var population_start = 10
|
|
export(int) var jobs_start = 0
|
|
export(int) var food_start = 20
|
|
export(int) var resources_start = 0
|
|
export(int) var effort_start = 20
|
|
export(int) var goods_start = 0
|
|
|
|
var game_resources = {
|
|
'population': population_start,
|
|
'jobs': jobs_start,
|
|
'food': food_start,
|
|
'resources': resources_start,
|
|
'effort': effort_start,
|
|
'goods': goods_start,
|
|
}
|
|
var turns = 0
|
|
|
|
var build_regex = RegEx.new()
|
|
var set_resource_regex = RegEx.new()
|
|
# Game rules ish
|
|
export(bool) var advance_turn_on_successful_command = true
|
|
|
|
var game_object_registry = {
|
|
# TileMap ID. this is a crap way. but hey. do it fast.
|
|
2: {
|
|
"name": 'road',
|
|
},
|
|
3: {
|
|
"name": 'road',
|
|
},
|
|
4: {
|
|
'name': 'road',
|
|
},
|
|
5: {
|
|
'name': 'road',
|
|
},
|
|
6: {
|
|
'name': 'bridge',
|
|
},
|
|
7: {
|
|
'name': 'house'
|
|
},
|
|
8: {
|
|
"name": 'farm',
|
|
"node_path": 'N/A',
|
|
}
|
|
}
|
|
|
|
func _ready():
|
|
# Called every time the node is added to the scene.
|
|
# Initialization here
|
|
self.register_command('help', funcref(self, "command_help"))
|
|
self.build_regex.compile("build (?<object_id>[a-z_]*) (?<x>\\d+),(?<y>\\d+)")
|
|
self.register_command('build', funcref(self, "command_build"))
|
|
self.register_command('skip', funcref(self, 'command_skip'))
|
|
self.set_level(self.level_path)
|
|
if not self.debug:
|
|
get_node('ui/left sidebar/toggleWorldButton').hide()
|
|
if self.debug:
|
|
self.register_command('set_resource', funcref(self, 'command_set_resource'))
|
|
self.set_resource_regex.compile('set_resource (?<resource_name>[a-z_]*) (?<value>\\d+)')
|
|
get_node('ui/right sidebar/resources').update_resources(self.game_resources)
|
|
|
|
func set_level(path):
|
|
self.level = load(self.level_path).instance()
|
|
self.level.hide()
|
|
# Display?
|
|
get_node('world').add_child(self.level)
|
|
get_node('ui/right sidebar/MapSizeContainer').set_level_size(self.level.get_level_size())
|
|
# Set objects / simulation parameters.
|
|
|
|
# Start time
|
|
self.turn_time_left = self.turn_max_length
|
|
get_node('ui/right sidebar/timer').set_time_max(self.turn_max_length)
|
|
self.update_timer()
|
|
|
|
func _process(delta):
|
|
# # Called every frame. Delta is time since last frame.
|
|
# # Update game logic here.
|
|
self.turn_time_left -= delta
|
|
if self.turn_time_left <= 0.0:
|
|
self.advance_turn()
|
|
self.update_timer()
|
|
|
|
func advance_turn():
|
|
self.turn_time_left = self.turn_max_length
|
|
# Find people who can't get to jobs
|
|
# Find unfilled jobs
|
|
# Report unconnected buildings
|
|
# Update stats: consume food, word, etc.
|
|
self.turns += 1
|
|
|
|
func update_timer():
|
|
get_node('ui/right sidebar/timer').set_time_left(self.turn_time_left)
|
|
|
|
# A player has hit enter
|
|
func _on_prompt_text_entered(new_text):
|
|
history_append(new_text)
|
|
if new_text:
|
|
run_command(new_text)
|
|
# @TODO Run the command
|
|
get_node('ui/prompt').clear()
|
|
|
|
func history_append(text, is_command_result = false, return_code = 0):
|
|
var n = get_node('ui/ViewportContainer/history')
|
|
if not n:
|
|
return
|
|
if is_command_result:
|
|
if return_code != 0:
|
|
n.push_color(Color(1.0, 0.0, 0.0, 1.0))
|
|
n.add_text(' > (%d) %s' %[return_code, text])
|
|
if return_code != 0:
|
|
n.pop()
|
|
else:
|
|
n.add_text("$ " + text)
|
|
n.newline()
|
|
|
|
func history_search():
|
|
pass
|
|
|
|
func run_command(text):
|
|
var result;
|
|
var callback = parse_command(text)
|
|
if not callback[1]:
|
|
result = [-1, 'Command "%s" not found' % callback[0]]
|
|
else:
|
|
result = callback[1].call_func(text)
|
|
self.history_append(result[1], true, result[0])
|
|
# Possibly advance the turn depending on the game rule.
|
|
if self.advance_turn_on_successful_command && result[0] == 0:
|
|
self.advance_turn()
|
|
|
|
func parse_command(text):
|
|
var a = text.split(' ')
|
|
if self.command_registry.has(a[0]):
|
|
return [a[0], self.command_registry[a[0]]]
|
|
return [a[0], false]
|
|
|
|
func register_command(name, callback):
|
|
self.command_registry[name] = callback;
|
|
|
|
func remove_command(name):
|
|
if self.command_registry.has(name):
|
|
self.command_registry.erase(name);
|
|
|
|
func command_help(text):
|
|
print("received command: '%s'" % text)
|
|
return [0, 'no!']
|
|
|
|
func command_set_resource(text):
|
|
var r = self.set_resource_regex.search(text)
|
|
if r == null:
|
|
return [-1, 'set_resource command could not match arguments. Format: set_resource <resource_name> <value>']
|
|
var resource_name = r.get_string(1)
|
|
if ! self.game_resources.has(resource_name):
|
|
return [-2, 'Resource "%s" does not exist' %resource_name]
|
|
var value = int(r.get_string(2))
|
|
self.set_game_resource(resource_name, value)
|
|
return [0, 'Set resource "%s" to %d' %[resource_name, value]]
|
|
|
|
func set_game_resource(name, value):
|
|
self.game_resources[name] = value
|
|
get_node('ui/right sidebar/resources').update_resources(self.game_resources)
|
|
|
|
func command_build(text):
|
|
var r = self.build_regex.search(text)
|
|
if r == null:
|
|
return [-1, 'Build command could not match arguments. Format: build <object_id> <x>,<y>']
|
|
var object_id = _get_obj_id_by_name(r.get_string(1))
|
|
if object_id == null:
|
|
return [-3, "Object with id '%s' is not registered" % r.get_string(1)]
|
|
var p = Vector2(int(r.get_string(2)), int(r.get_string(3)))
|
|
if not _is_in_level(p):
|
|
return [-4, "Point %d,%d is not in current level" %[p.x, p.y]]
|
|
var obj_exists = _obj_exists_in_level(p)
|
|
if obj_exists:
|
|
var obj_name = self.game_object_registry[_obj_in_level(p)]['name']
|
|
return [-5, "Object %s already exists at %d, %d" % [obj_name, p.x, p.y]]
|
|
# Check if base terrain is valid.
|
|
var terrain_object_id = self.level.get_node('terrain').get_cellv(p)
|
|
if terrain_object_id == -1:
|
|
return [-6, "No terrain underneath point at %d,%d" %[p.x, p.y]]
|
|
# grass
|
|
if terrain_object_id == 0 && object_id == 6:
|
|
return [-7, "Can not build over water at %d,%d" %[p.x, p.y]]
|
|
if terrain_object_id == 1 && object_id != 6:
|
|
return [-8, "Can not build over grass at %d,%d" %[p.x, p.y]]
|
|
# (optional) check resources
|
|
# Build
|
|
self.level.get_node('objects').set_cellv(p, object_id)
|
|
# (optional) spend resources
|
|
return [0, 'Built %s at %d,%d' % [self.game_object_registry[object_id]['name'], p.x, p.y]]
|
|
|
|
func _is_in_level(v):
|
|
if v.x >= self.level.origin.x and v.x <= self.level.origin.x + self.level.width and \
|
|
v.y >= self.level.origin.y and v.y <= self.level.origin.y + self.level.height:
|
|
return true
|
|
return false
|
|
|
|
func _get_obj_id_by_name(n):
|
|
for i in self.game_object_registry.keys():
|
|
if self.game_object_registry[i]['name'] == n:
|
|
return i
|
|
return null
|
|
|
|
func _obj_in_level(v):
|
|
var c = self.level.get_node('objects').get_cellv(v)
|
|
if c == -1:
|
|
return null
|
|
return c
|
|
|
|
func _obj_exists_in_level(v):
|
|
if _obj_in_level(v) != null:
|
|
return true
|
|
return false
|
|
|
|
|
|
func _on_toggleWorldButton_toggled(button_pressed):
|
|
print(button_pressed)
|
|
if self.level.is_visible_in_tree():
|
|
self.level.hide()
|
|
else:
|
|
self.level.show()
|
|
|
|
func command_skip(t):
|
|
self.advance_turn()
|
|
return [0, 'OK']
|
|
|
|
func _on_timer_skip_presssed():
|
|
print('a')
|
|
self.advance_turn()
|