diff --git a/scenes/ai/ai-player.tscn b/scenes/ai/ai-player.tscn new file mode 100644 index 0000000..8e2c194 --- /dev/null +++ b/scenes/ai/ai-player.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://scenes/player.tscn" type="PackedScene" id=1] +[ext_resource path="res://scripts/ai/ai-player.gd" type="Script" id=2] + +[node name="RigidBody" index="0" instance=ExtResource( 1 )] + +script = ExtResource( 2 ) +tp_camera = null +master_only = null + + diff --git a/scenes/ai/heroes/0.tscn b/scenes/ai/heroes/0.tscn new file mode 100644 index 0000000..d84ac67 --- /dev/null +++ b/scenes/ai/heroes/0.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://scenes/ai/ai-player.tscn" type="PackedScene" id=1] + +[node name="RigidBody" instance=ExtResource( 1 )] + +tp_camera = NodePath("TPCamera") +master_only = NodePath("MasterOnly") + + diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 5cc285a..73b18a3 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -20,6 +20,8 @@ func setup_options(): opts.add('-hero', 'r', 'Your choice of hero (index)') opts.add('-level', 'r', 'Your choice of level (index) - server only!') opts.add('-start-game', false, 'Join as a client and immediately start the game') + opts.add('-ai', false, 'Run this client as AI') + opts.add('-record', false, 'Record this play for AI later') opts.add('-h', false, "Print help") return opts @@ -56,6 +58,10 @@ func _ready(): call_deferred("_client_init") if o.get_value("-singleplayer"): call_deferred("_singleplayer_init") + if o.get_value("-ai"): + my_info.is_ai = true + if o.get_value("-record"): + my_info.record = true if o.get_value('-h'): o.print_help() quit() diff --git a/scripts/player.gd b/scripts/player.gd index c0cdaa2..2899f3d 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -22,6 +22,7 @@ var movement_charge = 0.15 # In percent per meter (except when heroes change tha const fall_height = -50 var debug_node +var recording = { "time": 0, "events": [], "spawn": Vector3() } slave var slave_transform = Basis() slave var slave_lin_v = Vector3() @@ -52,10 +53,45 @@ func spawn(): # So we don't all spawn on top of each other placement.x += rand_range(0, x_varies) placement.y += rand_range(0, y_varies) + recording.spawn = placement set_transform(Basis()) set_translation(placement) set_linear_velocity(Vector3()) +func event_to_obj(event): + var d = {} + if event is InputEventMouseMotion: + d.relative = {} + d.relative.x = event.relative.x + d.relative.y = event.relative.y + d.type = "motion" + if event is InputEventKey: + d.scancode = event.scancode + d.pressed = event.pressed + d.type = "key" + if event is InputEventMouseButton: + d.button_index = event.button_index + d.pressed = event.pressed + d.type = "mb" + return d + +func apply_dict(from, to): + if typeof(from) != TYPE_DICTIONARY: + return from + else: + for key in from: + to[key] = apply_dict(from[key], to[key]) + return to + +func obj_to_event(d): + var e + if d.type == "motion": e = InputEventMouseMotion.new() + if d.type == "key": e = InputEventKey.new() + if d.type == "mb": e = InputEventMouseButton.new() + d.erase("type") # Not in the event + apply_dict(d, e) + return e + func _input(event): if is_network_master(): if Input.is_action_just_pressed("switch_hero"): @@ -63,6 +99,8 @@ func _input(event): # Quit the game: if Input.is_action_pressed("quit"): quit() + if "record" in player_info: + recording.events.append([recording.time, event_to_obj(event)]) func toggle_mouse_capture(): if (Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED): @@ -194,6 +232,15 @@ func _exit_scene(): # Functions # ========= +func write_recording(): + var save = File.new() + var fname = "res://recordings/%d-%d-%d.rec" % [player_info.level, player_info.hero, randi() % 10000] + save.open(fname, File.WRITE) + save.store_line(to_json(recording)) + save.close() + # Quits the game: func quit(): + if "record" in player_info: + write_recording() get_tree().quit()