init public repo
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
extends Node
|
||||
|
||||
class_name Util
|
||||
|
||||
|
||||
static func clear_node(node:Node):
|
||||
for idx in range(node.get_child_count()):
|
||||
node.remove_child(node.get_child(0))
|
||||
|
||||
|
||||
static func curve_get_last_point(curve:Curve3D):
|
||||
return curve.get_point_position(curve.get_point_count() - 1)
|
||||
@@ -0,0 +1,50 @@
|
||||
extends Spatial
|
||||
|
||||
class_name Game
|
||||
|
||||
var players:Array
|
||||
var route:Route
|
||||
var first:Player
|
||||
var last:Player
|
||||
|
||||
const REMOVE_LAST = 2
|
||||
|
||||
|
||||
func _ready():
|
||||
route = get_node("route")
|
||||
if is_network_master():
|
||||
route.rpc("add_road",roads_factory.START, -1)
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_network_master():
|
||||
set_player_order()
|
||||
check_autotrack()
|
||||
|
||||
|
||||
func set_player_order():
|
||||
players = get_node("players").get_children()
|
||||
players.sort_custom(PlayerSorter,"sort")
|
||||
if players.size() > 0 && players[0] != first:
|
||||
new_first(players[0])
|
||||
if players.size() > 0 && players[players.size()-1] != last:
|
||||
last = players[players.size()-1]
|
||||
|
||||
|
||||
func new_first(player):
|
||||
if first != null:
|
||||
first.rpc("set_first",false)
|
||||
first = player
|
||||
first.rpc("set_first",true)
|
||||
|
||||
|
||||
func check_autotrack():
|
||||
if first != null:
|
||||
if first.position.x != -1 && route.get_last_road() != null:
|
||||
if first.position.x == route.get_last_road().get_index():
|
||||
route.rpc("add_road", roads_factory.STRAIGHT, -1)
|
||||
|
||||
|
||||
class PlayerSorter:
|
||||
static func sort(a, b):
|
||||
return a.position.x > b.position.x || a.position.x == b.position.x && a.position.y > b.position.y
|
||||
@@ -0,0 +1,152 @@
|
||||
extends Node
|
||||
|
||||
const MAX_PEERS = 4
|
||||
const LOBBY_READY_WAIT_TIME = 3
|
||||
|
||||
var Game = preload("res://scenes/game/Game.tscn")
|
||||
var Player = preload("res://scenes/player/Player.tscn")
|
||||
var HumanPlayer = preload("res://scenes/player/HumanPlayer.tscn")
|
||||
var BotPlayer = preload("res://scenes/player/BotPlayer.tscn")
|
||||
|
||||
var game:Game
|
||||
var players = {}
|
||||
|
||||
var game_name = ""
|
||||
var bots:bool = false
|
||||
var game_running:bool = false
|
||||
|
||||
signal players_changed(players)
|
||||
signal game_ready(ready)
|
||||
signal game_started()
|
||||
signal game_ended()
|
||||
|
||||
|
||||
remote func set_player(id, new_name:String = " ", new_color:Color = Color.black, new_ready:bool = false):
|
||||
players[id] = {"name" : new_name, "color" : new_color, "ready" : new_ready, "prepared" : false}
|
||||
emit_signal("players_changed", players)
|
||||
|
||||
if get_tree().is_network_server():
|
||||
var all_ready = true
|
||||
for p_id in players:
|
||||
rpc_id(id, "set_player", p_id, players[p_id].name, players[p_id].color, players[p_id].ready)
|
||||
rpc_id(p_id, "set_player", id, new_name, new_color, new_ready)
|
||||
all_ready = all_ready && players[p_id].ready
|
||||
rpc("game_ready", all_ready)
|
||||
|
||||
|
||||
func update_player(new_name:String = " ", new_color:Color = Color.black, new_ready:bool = false):
|
||||
if get_tree().is_network_server():
|
||||
set_player(get_tree().get_network_unique_id(), new_name, new_color, new_ready)
|
||||
else:
|
||||
rpc("set_player",get_tree().get_network_unique_id(), new_name, new_color, new_ready)
|
||||
|
||||
|
||||
remotesync func remove_player(id):
|
||||
players.erase(id)
|
||||
|
||||
if game != null:
|
||||
var game_players = game.get_node("players")
|
||||
if game_players.has_node(str(id)):
|
||||
game_players.remove_child(game_players.get_node(str(id)))
|
||||
|
||||
emit_signal("players_changed", players)
|
||||
|
||||
|
||||
remotesync func game_ready(all_ready:bool):
|
||||
if get_tree().is_network_server():
|
||||
if all_ready:
|
||||
game_running = true
|
||||
else:
|
||||
game_running = false
|
||||
emit_signal("game_ready", all_ready)
|
||||
|
||||
|
||||
remotesync func prepare_game():
|
||||
get_tree().set_pause(true)
|
||||
|
||||
game = Game.instance()
|
||||
get_tree().get_root().add_child(game)
|
||||
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
|
||||
for p_id in players:
|
||||
var controls
|
||||
var player = players[p_id]
|
||||
|
||||
var player_scene = Player.instance()
|
||||
player_scene.set_network_master(p_id)
|
||||
player_scene.set_name(str(p_id))
|
||||
game.get_node("players").add_child(player_scene)
|
||||
player_scene.set_player_name(player.name)
|
||||
player_scene.set_player_color(player.color)
|
||||
|
||||
if p_id == get_tree().get_network_unique_id():
|
||||
controls = HumanPlayer.instance()
|
||||
controls.set_name("HumanControl_" + str(p_id))
|
||||
game.add_child(controls)
|
||||
controls.set_player(player_scene.get_path())
|
||||
controls.set_network_master(p_id)
|
||||
|
||||
player_scene.set_start(player_scene.get_index())
|
||||
|
||||
if bots:
|
||||
for index in range(MAX_PEERS-players.size()):
|
||||
var bot_index = players.size() + index
|
||||
var player_scene = Player.instance()
|
||||
player_scene.set_name("bot_player" + str(bot_index))
|
||||
game.get_node("players").add_child(player_scene)
|
||||
player_scene.set_player_name("Bot " + str(bot_index))
|
||||
player_scene.set_player_color(Color(randf(),randf(),randf()))
|
||||
player_scene.add_to_group("bots")
|
||||
if get_tree().is_network_server():
|
||||
var bot = BotPlayer.instance()
|
||||
bot.set_name("bot" + str(bot_index))
|
||||
game.add_child(bot)
|
||||
bot.set_player(player_scene.get_path())
|
||||
bot.set_network_master(get_tree().get_network_unique_id())
|
||||
player_scene.set_start(bot_index)
|
||||
if players.has(get_tree().get_network_unique_id()):
|
||||
rpc_id(1, "player_prepared", get_tree().get_network_unique_id())
|
||||
|
||||
if get_tree().is_network_server():
|
||||
if players.has(get_tree().get_network_unique_id()):
|
||||
player_prepared(get_tree().get_network_unique_id())
|
||||
else:
|
||||
rpc_id(1, "player_prepared", get_tree().get_network_unique_id())
|
||||
|
||||
|
||||
remotesync func player_prepared(id):
|
||||
if get_tree().is_network_server():
|
||||
players[id].prepared = true
|
||||
var all_prepared = true
|
||||
for p_id in players:
|
||||
all_prepared = all_prepared && players[p_id].prepared
|
||||
if all_prepared:
|
||||
rpc("post_start_game")
|
||||
|
||||
|
||||
remotesync func post_start_game():
|
||||
get_tree().set_pause(false)
|
||||
emit_signal("game_started")
|
||||
|
||||
|
||||
remotesync func set_bots(has_bots:bool):
|
||||
bots = has_bots
|
||||
|
||||
|
||||
func quit_game():
|
||||
if game != null:
|
||||
game.queue_free()
|
||||
game = null
|
||||
|
||||
players.clear()
|
||||
if get_tree().get_root().has_node("multiplayer_menu"):
|
||||
get_tree().get_root().get_node("multiplayer_menu").show()
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
elif get_tree().get_root().has_node("main_menu"):
|
||||
get_tree().get_root().get_node("main_menu").show()
|
||||
game_running = false
|
||||
bots = false
|
||||
game_name = ""
|
||||
|
||||
emit_signal("game_ended")
|
||||
@@ -0,0 +1,58 @@
|
||||
extends Node
|
||||
|
||||
const FILE_PATH = "user://local_storage"
|
||||
|
||||
|
||||
func _ready():
|
||||
TranslationServer.set_locale(read_value("locale","en"))
|
||||
|
||||
|
||||
func read_content():
|
||||
var f = File.new()
|
||||
var err = f.open(FILE_PATH, File.READ)
|
||||
var content = {}
|
||||
if err == OK:
|
||||
content = parse_json(f.get_as_text())
|
||||
f.close()
|
||||
if content == null:
|
||||
content = {}
|
||||
return content
|
||||
|
||||
|
||||
func write_content(content:Dictionary):
|
||||
var f = File.new()
|
||||
var err = f.open(FILE_PATH, File.WRITE)
|
||||
#var err = f.open_encrypted_with_pass(FILE_PATH, File.WRITE, OS.get_unique_id())
|
||||
f.store_string(to_json(content))
|
||||
f.close()
|
||||
|
||||
|
||||
func write_value(key:String, value):
|
||||
var content = read_content()
|
||||
content[key] = value
|
||||
write_content(content)
|
||||
|
||||
|
||||
func read_value(key:String, default = null):
|
||||
var content = read_content()
|
||||
if content.has(key) && content.get(key) != null:
|
||||
return content.get(key)
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
func delete_value(key:String):
|
||||
var content = read_content()
|
||||
content.erase(key)
|
||||
write_content(content)
|
||||
|
||||
|
||||
func write_values(new_content:Dictionary):
|
||||
var content = read_content()
|
||||
for key in new_content:
|
||||
content[key] = new_content[key]
|
||||
write_content(content)
|
||||
|
||||
|
||||
func read_values():
|
||||
return read_content()
|
||||
@@ -0,0 +1,48 @@
|
||||
extends Spatial
|
||||
|
||||
class_name Route
|
||||
|
||||
signal road_added(road)
|
||||
signal road_removed(road)
|
||||
|
||||
|
||||
func get_last_road():
|
||||
if get_child_count() > 0:
|
||||
return get_child(get_child_count() - 1)
|
||||
else:
|
||||
return null
|
||||
|
||||
|
||||
func get_road(road_index):
|
||||
return get_child(road_index)
|
||||
|
||||
|
||||
remotesync func add_road(type, creator):
|
||||
var transform = get_global_transform()
|
||||
var last_road = get_last_road()
|
||||
if last_road != null:
|
||||
transform = last_road.get_global_transform();
|
||||
var curve = last_road.get_curve()
|
||||
transform = transform.translated(curve.get_point_position(curve.get_point_count() - 1))
|
||||
if last_road.get_end_rotation().length() != 0:
|
||||
transform.basis = transform.basis.rotated(last_road.get_end_rotation().normalized(), last_road.get_end_rotation().length())
|
||||
|
||||
var new_road = roads_factory.get_road_instance(type)
|
||||
new_road.set_global_transform(transform)
|
||||
new_road.set_preview(false)
|
||||
new_road.set_creator(creator)
|
||||
|
||||
if creator > 0:
|
||||
var player = gamestate.game.get_node(str(creator))
|
||||
if player != null:
|
||||
new_road.set_color(player.get_player_color())
|
||||
|
||||
add_child(new_road)
|
||||
|
||||
emit_signal("road_added", new_road)
|
||||
|
||||
|
||||
remotesync func remove_road(road_index):
|
||||
var road = get_child(road_index)
|
||||
remove_child(road)
|
||||
emit_signal("road_removed", road)
|
||||
@@ -0,0 +1,33 @@
|
||||
extends Control
|
||||
|
||||
var LobbyMenu = preload("res://scenes/menus/LobbyMenu.tscn")
|
||||
|
||||
|
||||
func _ready():
|
||||
find_node("bots").set_pressed(local_storage.read_value("bots", true))
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("host").grab_focus()
|
||||
|
||||
|
||||
func _on_host_pressed():
|
||||
var port = find_node("port").get_value()
|
||||
var bots = find_node("bots").is_pressed()
|
||||
var err = server.host_game(int(port), bots)
|
||||
|
||||
if err == OK:
|
||||
var lobby_menu = LobbyMenu.instance()
|
||||
get_tree().get_root().add_child(lobby_menu)
|
||||
|
||||
gamestate.set_player(get_tree().get_network_unique_id())
|
||||
|
||||
queue_free()
|
||||
else:
|
||||
_on_back_pressed()
|
||||
get_tree().get_root().get_node("multiplayer_menu").show_error_dialog(tr("ERROR_SERVER_CREATION"))
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
queue_free()
|
||||
get_tree().get_root().get_node("multiplayer_menu").show()
|
||||
@@ -0,0 +1,16 @@
|
||||
extends Control
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("join").grab_focus()
|
||||
|
||||
|
||||
func _on_join_pressed():
|
||||
var ip = find_node("ip").text
|
||||
var port = find_node("port").get_value()
|
||||
client.join_game(ip, int(port))
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
queue_free()
|
||||
@@ -0,0 +1,25 @@
|
||||
extends Control
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("resume").grab_focus()
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if Input.is_action_just_pressed("ui_cancel"):
|
||||
if is_visible_in_tree():
|
||||
hide()
|
||||
else:
|
||||
show()
|
||||
|
||||
|
||||
func _on_resume_pressed():
|
||||
hide()
|
||||
|
||||
|
||||
func _on_settings_pressed():
|
||||
pass
|
||||
|
||||
|
||||
func _on_end_pressed():
|
||||
gamestate.quit_game()
|
||||
@@ -0,0 +1,101 @@
|
||||
extends Control
|
||||
|
||||
onready var countdown_timer = get_node("countdown_timer")
|
||||
onready var player_settings = find_node("player_settings")
|
||||
onready var player_list = find_node("players")
|
||||
|
||||
|
||||
func _ready():
|
||||
if get_tree().get_root().has_node("multiplayer_menu"):
|
||||
get_tree().get_root().get_node("multiplayer_menu").hide()
|
||||
if get_tree().get_root().has_node("main_menu"):
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
|
||||
get_node("menu/back").connect("pressed",self,"_on_back_pressed")
|
||||
|
||||
gamestate.connect("players_changed", self, "_players_changed")
|
||||
gamestate.connect("game_ready", self, "_game_ready")
|
||||
gamestate.connect("game_started", self, "_game_started")
|
||||
client.connect("server_disconnected", self, "_server_disconnected")
|
||||
|
||||
player_settings.get_name_node().connect("text_changed",self,"_on_name_text_changed")
|
||||
player_settings.get_color_node().connect("color_changed",self,"_on_color_color_changed")
|
||||
player_settings.get_color_node().connect("draw",self,"_on_player_changed")
|
||||
|
||||
countdown_timer.set_wait_time(server.LOBBY_READY_WAIT_TIME)
|
||||
|
||||
if gamestate.game_name:
|
||||
find_node("server_name").set_text(gamestate.game_name)
|
||||
find_node("server_name").set_tooltip(gamestate.game_name)
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("ready").grab_focus()
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if not countdown_timer.is_stopped():
|
||||
get_node("countdown").text = str(int(countdown_timer.get_time_left()) + 1)
|
||||
|
||||
|
||||
func _players_changed(players):
|
||||
player_list.clear()
|
||||
for p_id in players:
|
||||
var player = players[p_id]
|
||||
if p_id == get_tree().get_network_unique_id():
|
||||
player_list.add_item(player.name + " (You)")
|
||||
else:
|
||||
player_list.add_item(player.name)
|
||||
player_list.set_item_custom_bg_color(player_list.get_item_count()-1, player.color)
|
||||
if player.ready:
|
||||
player_list.set_item_icon(player_list.get_item_count()-1, player_list.get_node("ready_icon").get_button_icon())
|
||||
else:
|
||||
player_list.set_item_icon(player_list.get_item_count()-1, player_list.get_node("not_ready_icon").get_button_icon())
|
||||
find_node("server_bots").set_pressed(gamestate.bots)
|
||||
|
||||
|
||||
func _game_ready(all_ready):
|
||||
if all_ready:
|
||||
get_node("countdown").show()
|
||||
countdown_timer.start()
|
||||
else:
|
||||
countdown_timer.stop()
|
||||
get_node("countdown").hide()
|
||||
|
||||
func _game_started():
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_name_text_changed(new_text):
|
||||
_on_player_changed()
|
||||
|
||||
|
||||
func _on_color_color_changed(color):
|
||||
_on_player_changed()
|
||||
|
||||
|
||||
func _on_ready_toggled(button_pressed):
|
||||
_on_player_changed()
|
||||
player_settings.get_name_node().set_editable(not button_pressed)
|
||||
player_settings.get_color_node().set_disabled(button_pressed)
|
||||
|
||||
|
||||
func _on_player_changed():
|
||||
var name = player_settings.get_name_node().text
|
||||
var color = player_settings.get_color_node().color
|
||||
var ready = find_node("ready").pressed
|
||||
gamestate.update_player(name,color,ready)
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
gamestate.quit_game()
|
||||
if get_tree().get_root().has_node("multiplayer_menu"):
|
||||
get_tree().get_root().get_node("multiplayer_menu").show()
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
elif get_tree().get_root().has_node("main_menu"):
|
||||
get_tree().get_root().get_node("main_menu").show()
|
||||
queue_free()
|
||||
|
||||
|
||||
func _server_disconnected():
|
||||
_on_back_pressed()
|
||||
@@ -0,0 +1,24 @@
|
||||
extends Control
|
||||
|
||||
onready var player_settings = find_node("player_settings")
|
||||
|
||||
|
||||
func _ready():
|
||||
find_node("bots").set_pressed(local_storage.read_value("bots", true))
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("start").grab_focus()
|
||||
|
||||
|
||||
func _on_start_pressed():
|
||||
var name = player_settings.get_name_node().text
|
||||
var color = player_settings.get_color_node().color
|
||||
var bots = find_node("bots").is_pressed()
|
||||
queue_free()
|
||||
server.local_game(name,color,bots)
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
queue_free()
|
||||
get_tree().get_root().get_node("main_menu").show()
|
||||
@@ -0,0 +1,43 @@
|
||||
extends Control
|
||||
|
||||
var MultiplayerMenu = preload("res://scenes/menus/MultiplayerMenu.tscn")
|
||||
var LocalGameMenu = preload("res://scenes/menus/LocalGameMenu.tscn")
|
||||
var SettingsMenu = preload("res://scenes/menus/SettingsMenu.tscn")
|
||||
|
||||
|
||||
func _ready():
|
||||
gamestate.connect("server_disconnected", self, "_server_disconnected")
|
||||
|
||||
func _draw():
|
||||
find_node("multiplayer").grab_focus()
|
||||
|
||||
func _on_multiplayer_pressed():
|
||||
var multiplayer_menu = MultiplayerMenu.instance()
|
||||
get_tree().get_root().add_child(multiplayer_menu)
|
||||
hide()
|
||||
|
||||
|
||||
func _on_practice_pressed():
|
||||
var local_game_menu = LocalGameMenu.instance()
|
||||
get_tree().get_root().add_child(local_game_menu)
|
||||
hide()
|
||||
|
||||
|
||||
func _on_settings_pressed():
|
||||
var settings_menu = SettingsMenu.instance()
|
||||
get_tree().get_root().add_child(settings_menu)
|
||||
hide()
|
||||
|
||||
|
||||
func _on_quit_pressed():
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _server_disconnected():
|
||||
show_error_dialog(tr("SERVER_DISCONNECTED"))
|
||||
|
||||
|
||||
func show_error_dialog(text:String):
|
||||
var dialog = get_node("error_dialog")
|
||||
dialog.set_text(text)
|
||||
dialog.popup_centered()
|
||||
@@ -0,0 +1,141 @@
|
||||
extends Control
|
||||
|
||||
var ServerCreateGameMenu = preload("res://scenes/menus/ServerCreateGameMenu.tscn")
|
||||
var LobbyMenu = preload("res://scenes/menus/LobbyMenu.tscn")
|
||||
var DirectHostMenu = preload("res://scenes/menus/DirectHostMenu.tscn")
|
||||
var DirectJoinMenu = preload("res://scenes/menus/DirectJoinMenu.tscn")
|
||||
|
||||
onready var games_list = get_node("menu/games")
|
||||
var games = []
|
||||
var selected_game = {}
|
||||
|
||||
|
||||
func _ready():
|
||||
get_node("menu/back").connect("pressed",self,"_on_back_pressed")
|
||||
client.connect("connection_succeeded", self, "_connection_succeeded")
|
||||
client.connect("connection_failed", self, "_connection_failed")
|
||||
client.connect("server_disconnected", self, "_server_disconnected")
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("refresh").grab_focus()
|
||||
|
||||
|
||||
func _on_multiplayer_menu_draw():
|
||||
get_games(find_node("open").is_pressed())
|
||||
get_node("refresh_timer").start()
|
||||
|
||||
|
||||
func _on_multiplayer_menu_hide():
|
||||
get_node("refresh_timer").stop()
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
queue_free()
|
||||
get_tree().get_root().get_node("main_menu").show()
|
||||
|
||||
|
||||
func _on_direct_host_pressed():
|
||||
var direct_host_menu = DirectHostMenu.instance()
|
||||
get_tree().get_root().add_child(direct_host_menu)
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
|
||||
|
||||
func _on_direct_join_pressed():
|
||||
var direct_join_menu = DirectJoinMenu.instance()
|
||||
get_tree().get_root().add_child(direct_join_menu)
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
|
||||
|
||||
func _on_open_toggled(button_pressed):
|
||||
get_games(button_pressed)
|
||||
|
||||
|
||||
func _on_refresh_pressed():
|
||||
if get_node("refresh_timer").is_stopped():
|
||||
get_node("refresh_timer").start()
|
||||
get_games(find_node("open").is_pressed())
|
||||
|
||||
|
||||
func _on_refresh_timer_timeout():
|
||||
get_games(find_node("open").is_pressed())
|
||||
|
||||
|
||||
func _server_disconnected():
|
||||
show_error_dialog(tr("SERVER_DISCONNECTED"))
|
||||
|
||||
|
||||
func show_error_dialog(text:String):
|
||||
var dialog = get_node("error_dialog")
|
||||
dialog.set_text(text)
|
||||
dialog.popup_centered()
|
||||
|
||||
|
||||
func get_games(only_open:bool):
|
||||
var req = game_server.http()
|
||||
req.connect_http(self,"_on_get_games")
|
||||
if only_open:
|
||||
req.get_request('client/games?open')
|
||||
else:
|
||||
req.get_request('client/games')
|
||||
|
||||
|
||||
func _on_get_games(result, response_code, headers, body):
|
||||
if result == OK && response_code == HTTPClient.RESPONSE_OK:
|
||||
find_node("create").set_disabled(false)
|
||||
find_node("open").set_disabled(false)
|
||||
var json = JSON.parse(body.get_string_from_utf8())
|
||||
games_list.clear()
|
||||
games = json.result
|
||||
for game in games:
|
||||
var name = game.name
|
||||
name += " ("
|
||||
name += str(game.player_count)
|
||||
name += "/4)"
|
||||
if game.bots:
|
||||
name += " [with Bots]"
|
||||
games_list.add_item(name)
|
||||
if game.running:
|
||||
games_list.set_item_icon(games_list.get_item_count()-1, games_list.get_node("running_icon").get_button_icon())
|
||||
elif game.has('private') && game.private:
|
||||
games_list.set_item_icon(games_list.get_item_count()-1, games_list.get_node("private_icon").get_button_icon())
|
||||
else:
|
||||
games_list.set_item_icon(games_list.get_item_count()-1, games_list.get_node("open_icon").get_button_icon())
|
||||
else:
|
||||
find_node("create").set_disabled(true)
|
||||
find_node("join").set_disabled(true)
|
||||
find_node("open").set_disabled(true)
|
||||
show_error_dialog(tr("SERVER_NO_CONNECTION"))
|
||||
get_node("refresh_timer").stop()
|
||||
|
||||
|
||||
func _on_create_pressed():
|
||||
var server_create_game_menu = ServerCreateGameMenu.instance()
|
||||
get_tree().get_root().add_child(server_create_game_menu)
|
||||
get_tree().get_root().get_node("main_menu").hide()
|
||||
|
||||
|
||||
func _on_join_pressed():
|
||||
client.join_game(game_server.SERVER_ADDR, int(selected_game['port']))
|
||||
|
||||
|
||||
func _connection_succeeded():
|
||||
var lobby_menu = LobbyMenu.instance()
|
||||
if selected_game && selected_game.has('name'):
|
||||
gamestate.game_name = selected_game.name
|
||||
get_tree().get_root().add_child(lobby_menu)
|
||||
get_node("refresh_timer").stop()
|
||||
hide()
|
||||
|
||||
|
||||
func _connection_failed():
|
||||
show_error_dialog(tr("CONNECTION_FAILED"))
|
||||
|
||||
|
||||
func _on_games_item_selected(index):
|
||||
selected_game = games[index]
|
||||
find_node("join").set_disabled(false)
|
||||
|
||||
|
||||
func _on_games_nothing_selected():
|
||||
find_node("join").set_disabled(true)
|
||||
@@ -0,0 +1,44 @@
|
||||
extends Control
|
||||
|
||||
|
||||
func _ready():
|
||||
var player_name = local_storage.read_value("player_name", false)
|
||||
var game_title = "New Game"
|
||||
if player_name:
|
||||
game_title += " by " + player_name
|
||||
find_node("name").set_text(game_title)
|
||||
find_node("bots").set_pressed(local_storage.read_value("bots", true))
|
||||
|
||||
|
||||
func _draw():
|
||||
find_node("create").grab_focus()
|
||||
|
||||
|
||||
func _on_create_pressed():
|
||||
var req = game_server.http()
|
||||
req.connect_http(self,"_on_game_created")
|
||||
var server_name = find_node("name").text
|
||||
var bots = 0
|
||||
if find_node("bots").is_pressed():
|
||||
bots = 1
|
||||
req.post_request('client/game/create', to_json({'name' : server_name, 'bots' : bots}))
|
||||
|
||||
|
||||
func _on_game_created(result, response_code, headers, body):
|
||||
if result == OK && response_code == HTTPClient.RESPONSE_OK:
|
||||
var json = JSON.parse(body.get_string_from_utf8())
|
||||
gamestate.game_name = json.result['name']
|
||||
client.join_game(game_server.SERVER_ADDR, int(json.result['port']))
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_name_text_changed(new_text):
|
||||
if new_text:
|
||||
find_node("create").set_disabled(false)
|
||||
else:
|
||||
find_node("create").set_disabled(true)
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
queue_free()
|
||||
get_tree().get_root().get_node("multiplayer_menu").show()
|
||||
@@ -0,0 +1,67 @@
|
||||
extends Control
|
||||
|
||||
onready var player_settings = find_node("settings_player")
|
||||
onready var game_tab = find_node("game")
|
||||
onready var controls_tab = find_node("controls")
|
||||
onready var graphics_tab = find_node("graphics")
|
||||
onready var system_tab = find_node("system")
|
||||
|
||||
var locale
|
||||
|
||||
|
||||
func _ready():
|
||||
get_node("menu/back").connect("pressed",self,"_on_back_pressed")
|
||||
find_node("bots").set_pressed(local_storage.read_value("bots", true))
|
||||
game_tab.set_name(tr("GAME"))
|
||||
controls_tab.set_name(tr("CONTROLS"))
|
||||
graphics_tab.set_name(tr("GRAPHICS"))
|
||||
system_tab.set_name(tr("SYSTEM"))
|
||||
|
||||
|
||||
func _on_back_pressed():
|
||||
queue_free()
|
||||
get_tree().get_root().get_node("main_menu").show()
|
||||
|
||||
|
||||
func _on_locales_item_selected(index):
|
||||
match index:
|
||||
0:
|
||||
locale = "en"
|
||||
1:
|
||||
locale = "de"
|
||||
_:
|
||||
locale = "en"
|
||||
TranslationServer.set_locale(locale)
|
||||
game_tab.set_name(tr("GAME"))
|
||||
controls_tab.set_name(tr("CONTROLS"))
|
||||
graphics_tab.set_name(tr("GRAPHICS"))
|
||||
system_tab.set_name(tr("SYSTEM"))
|
||||
|
||||
|
||||
func _init_locales():
|
||||
var locales = find_node("locales")
|
||||
locales.clear()
|
||||
locales.add_item(tr("LOCALE_EN"))
|
||||
locales.add_item(tr("LOCALE_DE"))
|
||||
locale = local_storage.read_value("locale","en")
|
||||
match locale:
|
||||
"en":
|
||||
locales.select(0)
|
||||
_on_locales_item_selected(0)
|
||||
"de":
|
||||
locales.select(1)
|
||||
_on_locales_item_selected(1)
|
||||
|
||||
|
||||
func _on_locales_tree_exiting():
|
||||
TranslationServer.set_locale(local_storage.read_value("locale","en"))
|
||||
|
||||
|
||||
func _on_save_pressed():
|
||||
var values = {}
|
||||
values['player_name'] = player_settings.get_name_node().text
|
||||
values['player_color'] = player_settings.get_color_node().color.to_html()
|
||||
values['bots'] = find_node("bots").is_pressed()
|
||||
values['locale'] = locale
|
||||
local_storage.write_values(values)
|
||||
_on_back_pressed()
|
||||
@@ -0,0 +1,89 @@
|
||||
tool
|
||||
|
||||
extends Control
|
||||
|
||||
onready var grid = find_node("grid")
|
||||
onready var key_dialog = get_node("key_dialog")
|
||||
|
||||
const INPUT_TYPE_KEY = 0
|
||||
const INPUT_TYPE_JOYPAD = 1
|
||||
|
||||
var last_action:String
|
||||
var last_event:InputEvent
|
||||
|
||||
var new_inputs = {}
|
||||
|
||||
func _ready():
|
||||
init_mapping()
|
||||
|
||||
|
||||
func init_mapping():
|
||||
new_inputs = {}
|
||||
for action in InputMap.get_actions():
|
||||
if action.begins_with("controls_"):
|
||||
var action_label = Label.new()
|
||||
action_label.set_name(action + "_label")
|
||||
action_label.set_text(action)
|
||||
grid.add_child(action_label)
|
||||
|
||||
var key_action_button = Button.new()
|
||||
key_action_button.set_h_size_flags(SIZE_SHRINK_CENTER)
|
||||
key_action_button.set_flat(true)
|
||||
key_action_button.set_meta("action",action)
|
||||
key_action_button.set_button_icon(get_node("icons/key").get_button_icon())
|
||||
|
||||
var joypad_action_button = Button.new()
|
||||
joypad_action_button.set_h_size_flags(SIZE_SHRINK_CENTER)
|
||||
joypad_action_button.set_flat(true)
|
||||
joypad_action_button.set_meta("action",action)
|
||||
|
||||
for mapping in InputMap.get_action_list(action):
|
||||
if mapping is InputEventKey:
|
||||
key_action_button.set_text(mapping.as_text())
|
||||
key_action_button.set_tooltip(mapping.as_text())
|
||||
elif mapping is InputEventJoypadButton:
|
||||
joypad_action_button.set_tooltip(str(mapping.button_index))
|
||||
if has_node("icons/joypad/" + str(mapping.button_index)):
|
||||
joypad_action_button.set_button_icon(get_node("icons/joypad/" + str(mapping.button_index)).get_button_icon())
|
||||
else:
|
||||
joypad_action_button.set_button_icon(get_node("icons/joypad/other").get_button_icon())
|
||||
joypad_action_button.set_text(str(mapping.button_index))
|
||||
|
||||
grid.add_child(key_action_button)
|
||||
key_action_button.connect("pressed",self,"_on_button_pressed",[action, INPUT_TYPE_KEY])
|
||||
|
||||
grid.add_child(joypad_action_button)
|
||||
joypad_action_button.connect("pressed",self,"_on_button_pressed",[action, INPUT_TYPE_JOYPAD])
|
||||
|
||||
func _unhandled_input(event):
|
||||
if key_dialog.is_visible_in_tree():
|
||||
if key_dialog.get_meta("type") == INPUT_TYPE_KEY && event is InputEventKey:
|
||||
last_event = event
|
||||
key_dialog.set_text(tr(last_event.as_text()))
|
||||
key_dialog.get_ok().set_disabled(false)
|
||||
elif key_dialog.get_meta("type") == INPUT_TYPE_JOYPAD && event is InputEventJoypadButton:
|
||||
last_event = event
|
||||
key_dialog.set_text(last_event.as_text())
|
||||
key_dialog.get_ok().set_disabled(false)
|
||||
|
||||
|
||||
func _on_button_pressed(action, type):
|
||||
last_action = action
|
||||
last_event = null
|
||||
key_dialog.set_text(tr("PRESS_KEY"))
|
||||
key_dialog.set_meta("type", type)
|
||||
key_dialog.connect("confirmed",self,"_on_dialog_confirmed")
|
||||
key_dialog.get_ok().set_disabled(true)
|
||||
key_dialog.popup_centered()
|
||||
|
||||
|
||||
func _on_dialog_confirmed(type):
|
||||
if not new_inputs.has(last_action):
|
||||
new_inputs[last_action] = {}
|
||||
match key_dialog.get_meta("type"):
|
||||
INPUT_TYPE_KEY:
|
||||
if last_event is InputEventKey:
|
||||
new_inputs[last_action]["key"] = OS.get_scancode_string(last_event.scancode)
|
||||
INPUT_TYPE_JOYPAD:
|
||||
if last_event is InputEventJoypadButton:
|
||||
new_inputs[last_action]["joypad"] = last_event.button_index
|
||||
@@ -0,0 +1,14 @@
|
||||
extends Control
|
||||
|
||||
|
||||
func _ready():
|
||||
get_name_node().set_text(local_storage.read_value("player_name", "Player"))
|
||||
get_color_node().set_pick_color(Color(local_storage.read_value("player_color", "#000000")))
|
||||
|
||||
|
||||
func get_name_node():
|
||||
return find_node("name")
|
||||
|
||||
|
||||
func get_color_node():
|
||||
return find_node("color")
|
||||
@@ -0,0 +1,44 @@
|
||||
extends Node
|
||||
|
||||
signal connection_failed()
|
||||
signal connection_succeeded()
|
||||
signal server_disconnected()
|
||||
|
||||
|
||||
func join_game(ip, port:int):
|
||||
get_tree().connect("connected_to_server", self, "_connected_ok")
|
||||
get_tree().connect("connection_failed", self, "_connected_fail")
|
||||
get_tree().connect("server_disconnected", self, "_server_disconnected")
|
||||
gamestate.connect("game_ended",self,"_game_ended")
|
||||
var host = NetworkedMultiplayerENet.new()
|
||||
host.create_client(ip, port)
|
||||
get_tree().set_network_peer(host)
|
||||
|
||||
|
||||
func _connected_ok():
|
||||
gamestate.rpc("set_player", get_tree().get_network_unique_id())
|
||||
emit_signal("connection_succeeded")
|
||||
|
||||
|
||||
func _connected_fail():
|
||||
get_tree().disconnect("connected_to_server", self, "_connected_ok")
|
||||
get_tree().disconnect("connection_failed", self, "_connected_fail")
|
||||
get_tree().disconnect("server_disconnected", self, "_server_disconnected")
|
||||
get_tree().set_network_peer(null)
|
||||
emit_signal("connection_failed")
|
||||
|
||||
|
||||
func _server_disconnected():
|
||||
gamestate.quit_game()
|
||||
emit_signal("server_disconnected")
|
||||
|
||||
|
||||
func _game_ended():
|
||||
get_tree().disconnect("connected_to_server", self, "_connected_ok")
|
||||
get_tree().disconnect("connection_failed", self, "_connected_fail")
|
||||
get_tree().disconnect("server_disconnected", self, "_server_disconnected")
|
||||
|
||||
gamestate.disconnect("game_ended",self,"_game_ended")
|
||||
|
||||
get_tree().set_refuse_new_network_connections(false)
|
||||
get_tree().set_network_peer(null)
|
||||
@@ -0,0 +1,14 @@
|
||||
extends Spatial
|
||||
|
||||
class_name GameServer
|
||||
|
||||
const SERVER_ADDR = "mur-server.lh8.de"
|
||||
const API_ADDR = "https://" + SERVER_ADDR + "/"
|
||||
const HEADERS = ["Content-Type: application/json"]
|
||||
const SSL = false
|
||||
|
||||
|
||||
func http():
|
||||
var game_server_requests = GameServerRequests.new()
|
||||
add_child(game_server_requests)
|
||||
return game_server_requests
|
||||
@@ -0,0 +1,35 @@
|
||||
extends Spatial
|
||||
|
||||
class_name GameServerRequests
|
||||
|
||||
var http:HTTPRequest
|
||||
|
||||
|
||||
func _ready():
|
||||
http = HTTPRequest.new()
|
||||
add_child(http)
|
||||
http.connect("request_completed",self, "_self_destroy")
|
||||
|
||||
|
||||
func connect_http(node,function):
|
||||
http.connect("request_completed",node,function)
|
||||
|
||||
|
||||
func get_request(path:String):
|
||||
http.request(game_server.API_ADDR + path, game_server.HEADERS, game_server.SSL, HTTPClient.METHOD_GET)
|
||||
|
||||
|
||||
func post_request(path:String, data:String = ""):
|
||||
http.request(game_server.API_ADDR + path, game_server.HEADERS, game_server.SSL, HTTPClient.METHOD_POST, data)
|
||||
|
||||
|
||||
func put_request(path:String, data:String = ""):
|
||||
http.request(game_server.API_ADDR + path, game_server.HEADERS, game_server.SSL, HTTPClient.METHOD_PUT, data)
|
||||
|
||||
|
||||
func delete_request(path:String, data:String = ""):
|
||||
http.request(game_server.API_ADDR + path, game_server.HEADERS, game_server.SSL, HTTPClient.METHOD_DELETE, data)
|
||||
|
||||
|
||||
func _self_destroy(result, response_code, headers, body):
|
||||
queue_free()
|
||||
@@ -0,0 +1,157 @@
|
||||
extends Node
|
||||
|
||||
const MAX_PEERS = 4
|
||||
const LOBBY_READY_WAIT_TIME = 3
|
||||
const EMPTY_WAIT_TIME = 30
|
||||
|
||||
var port:int = -1
|
||||
var dedicated_server:bool = false
|
||||
var server_secret:String = ""
|
||||
var server_id:String = "[GAME:-1] "
|
||||
|
||||
var timer:Timer
|
||||
|
||||
signal server_error(type, data)
|
||||
|
||||
|
||||
func _ready():
|
||||
for argument in OS.get_cmdline_args():
|
||||
if argument.split("=")[0] == "--port":
|
||||
dedicated_server = true
|
||||
port = int(argument.split("=")[1])
|
||||
if argument.split("=")[0] == "--server-id":
|
||||
server_id = "[GAME:" + str(argument.split("=")[1]) + "] "
|
||||
if argument.split("=")[0] == "--secret":
|
||||
server_secret=argument.split("=")[1]
|
||||
if argument.split("=")[0] == "--bots":
|
||||
gamestate.set_bots(bool(int(argument.split("=")[1])))
|
||||
|
||||
if dedicated_server:
|
||||
var err = host_game(port)
|
||||
if err == OK:
|
||||
print(server_id + "New game hosted: port=" + str(port) + " secret=" + str(server_secret) + " bots=" + str(gamestate.bots))
|
||||
else:
|
||||
print(server_id + "Could not create Server! (port=" + str(port) + " secret=" + str(server_secret) + ")")
|
||||
quit_server()
|
||||
|
||||
|
||||
func host_game(port:int, set_bots:bool = false):
|
||||
var host = NetworkedMultiplayerENet.new()
|
||||
var err = host.create_server(port, MAX_PEERS)
|
||||
get_tree().set_network_peer(host)
|
||||
|
||||
get_tree().connect("network_peer_connected", self, "_client_connected")
|
||||
get_tree().connect("network_peer_disconnected", self,"_client_disconnected")
|
||||
|
||||
gamestate.connect("players_changed",self,"_players_changed")
|
||||
gamestate.connect("game_ready",self,"_game_ready")
|
||||
gamestate.connect("game_ended",self,"_game_ended")
|
||||
|
||||
if set_bots:
|
||||
gamestate.bots = true
|
||||
|
||||
if timer == null:
|
||||
timer = Timer.new()
|
||||
timer.set_name("timer")
|
||||
timer.set_timer_process_mode(Timer.TIMER_PROCESS_PHYSICS)
|
||||
timer.set_one_shot(true)
|
||||
timer.set_autostart(false)
|
||||
add_child(timer)
|
||||
|
||||
if err != OK:
|
||||
emit_signal("server_error", "HOST", err)
|
||||
|
||||
return err
|
||||
|
||||
|
||||
func local_game(name:String, color:Color, bots:bool):
|
||||
var localhost = NetworkedMultiplayerENet.new()
|
||||
localhost.create_server(0, 0)
|
||||
get_tree().set_network_peer(localhost)
|
||||
gamestate.bots = bots
|
||||
gamestate.set_player(get_tree().get_network_unique_id(), name, color)
|
||||
gamestate.prepare_game()
|
||||
gamestate.post_start_game()
|
||||
|
||||
|
||||
func update_server_data():
|
||||
var req = game_server.http()
|
||||
req.put_request("game",to_json({'secret' : server_secret, 'player_count' : gamestate.players.size(), 'running' : gamestate.game_running}))
|
||||
|
||||
func _client_connected(id):
|
||||
if get_tree().is_network_server():
|
||||
if dedicated_server:
|
||||
print(server_id + "peer connected: " + str(id))
|
||||
gamestate.rpc_id(id, "set_bots" ,gamestate.bots)
|
||||
if not timer.is_stopped():
|
||||
timer.disconnect("timeout",self,"quit_server")
|
||||
timer.stop()
|
||||
|
||||
|
||||
func _client_disconnected(id):
|
||||
if get_tree().is_network_server():
|
||||
if dedicated_server:
|
||||
print(server_id + "peer disconnected: " + str(id))
|
||||
if gamestate.game_running:
|
||||
emit_signal("server_error", "DISCONNECTED", [id])
|
||||
gamestate.rpc("remove_player" ,id)
|
||||
else:
|
||||
gamestate.rpc("remove_player" ,id)
|
||||
|
||||
|
||||
func _players_changed(players):
|
||||
if get_tree().is_network_server():
|
||||
if dedicated_server:
|
||||
update_server_data()
|
||||
if players.empty():
|
||||
if gamestate.game_running:
|
||||
print(server_id + "All players disconnected, close server.")
|
||||
quit_server()
|
||||
else:
|
||||
print(server_id + "All players disconnected, wait for closing...")
|
||||
timer.set_wait_time(EMPTY_WAIT_TIME)
|
||||
timer.connect("timeout",self,"quit_server",[true])
|
||||
timer.start()
|
||||
|
||||
|
||||
func quit_server(triggered:bool = false):
|
||||
if dedicated_server && triggered:
|
||||
print(server_id + "Closing time over...quit")
|
||||
var req = game_server.http()
|
||||
req.connect_http(self,"_on_delete_server")
|
||||
req.delete_request("game",to_json({'secret' : server_secret}))
|
||||
|
||||
|
||||
func _on_delete_server(result, response_code, headers, body):
|
||||
if result != OK || response_code != HTTPClient.RESPONSE_OK:
|
||||
print(server_id + "ERROR: _on_delete_server, server might be in undefined state!")
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _start_game():
|
||||
if get_tree().is_network_server():
|
||||
get_tree().set_refuse_new_network_connections(true)
|
||||
gamestate.rpc("prepare_game")
|
||||
|
||||
|
||||
func _game_ready(all_ready):
|
||||
if get_tree().is_network_server():
|
||||
if all_ready:
|
||||
timer.set_wait_time(LOBBY_READY_WAIT_TIME)
|
||||
timer.connect("timeout",self,"_start_game")
|
||||
timer.start()
|
||||
else:
|
||||
timer.disconnect("timeout",self,"_start_game")
|
||||
timer.stop()
|
||||
|
||||
|
||||
func _game_ended():
|
||||
get_tree().disconnect("network_peer_connected", self, "_client_connected")
|
||||
get_tree().disconnect("network_peer_disconnected", self,"_client_disconnected")
|
||||
|
||||
gamestate.disconnect("players_changed",self,"_players_changed")
|
||||
gamestate.disconnect("game_ready",self,"_game_ready")
|
||||
gamestate.disconnect("game_ended",self,"_game_ended")
|
||||
|
||||
get_tree().set_refuse_new_network_connections(false)
|
||||
get_tree().set_network_peer(null)
|
||||
@@ -0,0 +1,74 @@
|
||||
extends Spatial
|
||||
|
||||
class_name BaseInventory
|
||||
|
||||
var road_straights = [
|
||||
roads_factory.BUMP,
|
||||
roads_factory.BUMP_SMALL,
|
||||
roads_factory.STRAIGHT,
|
||||
roads_factory.STRAIGHT_SMALL,
|
||||
]
|
||||
|
||||
var roads_left = [
|
||||
roads_factory.CURVE_LEFT,
|
||||
roads_factory.CURVE_LARGE_LEFT,
|
||||
roads_factory.CURVE_SMALL_LEFT,
|
||||
roads_factory.SKEW_LEFT,
|
||||
roads_factory.CURVED_LEFT,
|
||||
]
|
||||
|
||||
var roads_right = [
|
||||
roads_factory.CURVE_RIGHT,
|
||||
roads_factory.CURVE_LARGE_RIGHT,
|
||||
roads_factory.CURVE_SMALL_RIGHT,
|
||||
roads_factory.SKEW_RIGHT,
|
||||
roads_factory.CURVED_RIGHT,
|
||||
]
|
||||
|
||||
var roads_up = [
|
||||
roads_factory.RAMP_UP,
|
||||
roads_factory.RAMP_CURVED_UP,
|
||||
roads_factory.RAMP_SMALL_UP,
|
||||
]
|
||||
|
||||
var roads_down = [
|
||||
roads_factory.RAMP_DOWN,
|
||||
roads_factory.RAMP_CURVED_DOWN,
|
||||
roads_factory.RAMP_SMALL_DOWN,
|
||||
]
|
||||
|
||||
var roads_special = [
|
||||
roads_factory.LOOP,
|
||||
]
|
||||
|
||||
var roads = [ road_straights, roads_left, roads_right, roads_up, roads_down, roads_special ]
|
||||
|
||||
var player:Player
|
||||
var route:Route
|
||||
var item:Road
|
||||
var type:int = 0
|
||||
var index:int = 0
|
||||
|
||||
signal item_changed(index, player)
|
||||
|
||||
|
||||
func _ready():
|
||||
route = gamestate.game.route
|
||||
|
||||
|
||||
func set_player(new_player:Player):
|
||||
player = new_player
|
||||
|
||||
|
||||
func set_item():
|
||||
if is_network_master():
|
||||
if item:
|
||||
item.free()
|
||||
item = roads_factory.get_road_instance(roads[type][index])
|
||||
|
||||
if player != null:
|
||||
item.set_color(player.get_player_color())
|
||||
|
||||
item.rotate_y(PI/2)
|
||||
|
||||
emit_signal("item_changed", roads[type][index], player)
|
||||
@@ -0,0 +1,56 @@
|
||||
extends Spatial
|
||||
|
||||
var player:Player
|
||||
|
||||
const MAX_ROAD_INDEX = 1
|
||||
var error_rate:float = 0.00
|
||||
var underspeed_rate:float = 0.00
|
||||
|
||||
|
||||
func _ready():
|
||||
randomize()
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_network_master() && player != null:
|
||||
if player.is_out:
|
||||
if player.is_resetable:
|
||||
player.reset()
|
||||
else:
|
||||
if player.get_road() != null:
|
||||
var rate = randf()
|
||||
var road = player.get_road()
|
||||
var road_index = 0
|
||||
var speed_constrain = 0.0
|
||||
while road != null && road_index < MAX_ROAD_INDEX:
|
||||
for index in range(road.speed_constrains.size()):
|
||||
var constrain = road.speed_constrains[index]
|
||||
if constrain.z > 0:
|
||||
speed_constrain = max(speed_constrain, constrain.z)
|
||||
elif constrain.z < 0:
|
||||
speed_constrain = min(speed_constrain, constrain.z)
|
||||
road = player.route.get_road(road.get_index() + 1)
|
||||
road_index += 1
|
||||
|
||||
var speed = player.current_speed
|
||||
if speed_constrain < 0:
|
||||
player.thrust = 1
|
||||
elif speed_constrain > 0 && speed > speed_constrain:
|
||||
player.thrust = -1
|
||||
elif rate > underspeed_rate:
|
||||
player.thrust = 1
|
||||
else:
|
||||
player.thrust = 0
|
||||
|
||||
|
||||
func set_player(path:String):
|
||||
player = get_node(path)
|
||||
get_node("inventory").set_player(player)
|
||||
|
||||
|
||||
func set_error_rate(new_error_rate:float):
|
||||
error_rate = new_error_rate
|
||||
|
||||
|
||||
func set_underspeed_rate(new_underspeed_rate:float):
|
||||
underspeed_rate = new_underspeed_rate
|
||||
@@ -0,0 +1,22 @@
|
||||
extends BaseInventory
|
||||
|
||||
var rand:RandomNumberGenerator = RandomNumberGenerator.new()
|
||||
|
||||
|
||||
func _ready():
|
||||
rand.randomize()
|
||||
|
||||
|
||||
func _on_raceCar_road_entered(road):
|
||||
if is_network_master():
|
||||
if player != null:
|
||||
if player.is_in_group("first"):
|
||||
if route.get_last_road().get_index() <= (road.get_index() +2):
|
||||
type = rand.randi_range(0,roads.size() -2) # TODO: remove special, loop need fixes!
|
||||
index = rand.randi_range(0, roads[type].size() -1)
|
||||
route.rpc("add_road", roads[type][index], player.get_index())
|
||||
|
||||
|
||||
func set_player(new_player:Player):
|
||||
player = new_player
|
||||
player.race_car.connect("road_entered",self,"_on_raceCar_road_entered")
|
||||
@@ -0,0 +1,49 @@
|
||||
extends Spatial
|
||||
|
||||
var player:Player
|
||||
onready var camera:InterpolatedCamera = get_node("camera")
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_network_master() && player != null:
|
||||
if player.is_out:
|
||||
camera.set_speed(0.1)
|
||||
if player.timer.get_time_left() > 0:
|
||||
get_node("hud/reset").set_text(str(int(player.timer.get_time_left()) + 1))
|
||||
else:
|
||||
get_node("hud/reset").set_text(tr("RESET"))
|
||||
if Input.is_action_pressed("controls_reset"):
|
||||
if player.reset():
|
||||
camera.set_speed(10)
|
||||
get_node("hud/reset").set_text("")
|
||||
else:
|
||||
if Input.is_action_pressed("controls_thrust"):
|
||||
player.thrust = 1
|
||||
elif Input.is_action_pressed("controls_break"):
|
||||
player.thrust = -1
|
||||
else:
|
||||
player.thrust = 0
|
||||
|
||||
get_node("hud/speed").set_text(str(player.current_speed))
|
||||
|
||||
if Input.is_action_pressed("debug_camera_1"):
|
||||
set_debug_camera(0)
|
||||
elif Input.is_action_pressed("debug_camera_2"):
|
||||
set_debug_camera(1)
|
||||
elif Input.is_action_pressed("debug_camera_3"):
|
||||
set_debug_camera(2)
|
||||
elif Input.is_action_pressed("debug_camera_4"):
|
||||
set_debug_camera(3)
|
||||
|
||||
|
||||
func set_player(path:String):
|
||||
player = get_node(path)
|
||||
get_node("inventory").set_player(player)
|
||||
camera.set_target_path(player.find_node("CameraTarget").get_path())
|
||||
camera.set_interpolation_enabled(true)
|
||||
camera.set_speed(10)
|
||||
|
||||
|
||||
func set_debug_camera(idx):
|
||||
if idx < gamestate.game.players.get_child_count():
|
||||
camera.set_target_path(gamestate.game.players.get_child(idx).find_node("CameraTarget").get_path())
|
||||
@@ -0,0 +1,62 @@
|
||||
extends BaseInventory
|
||||
|
||||
var view:Spatial
|
||||
var preview:Spatial
|
||||
|
||||
|
||||
func _ready():
|
||||
view = get_node("view")
|
||||
preview = get_node("preview")
|
||||
var hud_track = get_node("../hud/inventory/track")
|
||||
hud_track.get_texture().set_viewport_path_in_scene(str(get_path()) + "/viewport")
|
||||
connect("item_changed",self,"_on_item_changed")
|
||||
connect("item_changed",preview,"_on_inventory_item_changed")
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_network_master():
|
||||
if player != null:
|
||||
if not player.is_out && player.is_in_group("first"):
|
||||
get_node("../hud/inventory").show()
|
||||
if item == null:
|
||||
set_item()
|
||||
if preview.item:
|
||||
preview.item.show()
|
||||
if Input.is_action_just_pressed("controls_add_road"):
|
||||
route.rpc("add_road", roads[type][index], player.get_index())
|
||||
if Input.is_action_just_pressed("controls_prev_road_type"):
|
||||
type -= 1
|
||||
if type < 0:
|
||||
type = roads.size() -1
|
||||
index = 0
|
||||
set_item()
|
||||
if Input.is_action_just_pressed("controls_next_road_type"):
|
||||
type += 1
|
||||
if type > roads.size() - 1:
|
||||
type = 0
|
||||
index = 0
|
||||
set_item()
|
||||
if Input.is_action_just_pressed("controls_prev_road_variant"):
|
||||
index -= 1
|
||||
if index < 0:
|
||||
index = roads[type].size() -1
|
||||
set_item()
|
||||
if Input.is_action_just_pressed("controls_next_road_variant"):
|
||||
index += 1
|
||||
if index > roads[type].size() - 1:
|
||||
index = 0
|
||||
set_item()
|
||||
else:
|
||||
get_node("../hud/inventory").hide()
|
||||
if preview.item:
|
||||
preview.item.hide()
|
||||
|
||||
|
||||
func _on_item_changed(road_identifier, player):
|
||||
if is_network_master():
|
||||
if view.get_child_count() > 0:
|
||||
view.remove_child(view.get_child(0))
|
||||
|
||||
view.add_child(item)
|
||||
|
||||
get_node("../hud/inventory/type").set_text(tr(road_identifier))
|
||||
@@ -0,0 +1,32 @@
|
||||
extends Spatial
|
||||
|
||||
class_name Preview
|
||||
|
||||
var player:Player
|
||||
var item:Road
|
||||
|
||||
|
||||
func _ready():
|
||||
gamestate.game.route.connect("road_added",self,"_on_route_road_added")
|
||||
|
||||
|
||||
func _on_route_road_added(road):
|
||||
if is_network_master() && item:
|
||||
var transform = road.get_global_transform();
|
||||
var curve = road.get_curve()
|
||||
transform = transform.translated(curve.get_point_position(curve.get_point_count() -1))
|
||||
if road.get_end_rotation().length() != 0:
|
||||
transform.basis = transform.basis.rotated(road.get_end_rotation().normalized(), road.get_end_rotation().length())
|
||||
item.set_global_transform(transform)
|
||||
|
||||
|
||||
func _on_inventory_item_changed(road_identifier, player):
|
||||
if is_network_master():
|
||||
if item:
|
||||
item.free()
|
||||
item = roads_factory.get_road_instance(road_identifier)
|
||||
item.set_preview(true)
|
||||
if player != null:
|
||||
item.set_color(player.get_player_color())
|
||||
add_child(item)
|
||||
_on_route_road_added(gamestate.game.route.get_last_road())
|
||||
@@ -0,0 +1,230 @@
|
||||
extends Node
|
||||
|
||||
class_name Player
|
||||
|
||||
const MAX_SPEED:float = 0.2
|
||||
|
||||
const START_OFFSET = [1.70223, 1.20223, 0.702227, 0.202227 ]
|
||||
const LANE_OFFSET = [-0.085, 0.085, -0.255, 0.255 ]
|
||||
|
||||
export var player_color:Color
|
||||
var player_name:String
|
||||
|
||||
var thrust:int = 0
|
||||
var current_speed:float = 0.0
|
||||
|
||||
export var speed_factor:float = 0.001
|
||||
export var brake_factor:float = 2.0
|
||||
export var friction_brake_factor:float = 0.8
|
||||
|
||||
onready var race_car = get_node("Path/PathFollow/raceCar")
|
||||
onready var timer:Timer = get_node("ResetTimer")
|
||||
onready var path:Path = get_node("Path")
|
||||
onready var follow:PathFollow = get_node("Path/PathFollow")
|
||||
onready var route:Route
|
||||
|
||||
var lane:int
|
||||
|
||||
var start_init:bool = true
|
||||
var has_next:bool = false
|
||||
var is_resetable:bool = false
|
||||
var buffered_curve:Curve3D
|
||||
var buffered_translate:Vector3 = Vector3(0,0,0)
|
||||
var buffered_rotation:Vector3 = Vector3(0,0,0)
|
||||
var last_rotation:Vector3 = Vector3(0,0,0)
|
||||
var torque_penalty:Vector3
|
||||
var force_penalty:Vector3
|
||||
var path_penalty:float
|
||||
|
||||
var is_out:bool = false
|
||||
var position:Vector2
|
||||
|
||||
puppet var slave_position:Vector2
|
||||
|
||||
|
||||
func _ready():
|
||||
route = gamestate.game.route
|
||||
race_car.road_ray.set_collision_mask_bit(get_index(),1)
|
||||
path.curve = path.curve.duplicate()
|
||||
path.curve.set_bake_interval(0.05)
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_network_master():
|
||||
if not is_out:
|
||||
var max_speed = MAX_SPEED
|
||||
|
||||
if get_road() != null:
|
||||
var road = get_road()
|
||||
if is_in_group("first"):
|
||||
max_speed *= road.get_first_speed_factor()
|
||||
if road.get_creator() == get_index():
|
||||
max_speed *= road.get_creator_speed_factor()
|
||||
else:
|
||||
max_speed *= road.get_chasers_speed_factor()
|
||||
|
||||
|
||||
if thrust == 1:
|
||||
current_speed += speed_factor
|
||||
elif thrust == -1:
|
||||
current_speed -= speed_factor * brake_factor
|
||||
else:
|
||||
current_speed -= speed_factor * friction_brake_factor
|
||||
|
||||
if current_speed >= max_speed:
|
||||
current_speed = max_speed
|
||||
elif current_speed < 0:
|
||||
current_speed = 0
|
||||
|
||||
follow.set_offset(follow.get_offset() + current_speed)
|
||||
|
||||
if follow.get_offset() < 0:
|
||||
follow.set_offset(0)
|
||||
|
||||
if has_next && (path.curve.get_point_count() == 0 || follow.get_unit_offset() >= 1.0):
|
||||
has_next = false
|
||||
if path.curve.get_point_count() > 0:
|
||||
path.curve.clear_points()
|
||||
|
||||
path.curve.set_bake_interval(0.05)
|
||||
for i in range(buffered_curve.get_point_count()):
|
||||
var _pos = buffered_curve.get_point_position(i)
|
||||
var _in = buffered_curve.get_point_in(i)
|
||||
var _out = buffered_curve.get_point_out(i)
|
||||
if buffered_rotation.length() != 0:
|
||||
_pos = _pos.rotated(buffered_rotation.normalized(), buffered_rotation.length())
|
||||
_in = _in.rotated(buffered_rotation.normalized(), buffered_rotation.length())
|
||||
_out = _out.rotated(buffered_rotation.normalized(), buffered_rotation.length())
|
||||
path.curve.add_point(buffered_translate + _pos, _in, _out)
|
||||
path.curve.set_point_tilt(i, buffered_curve.get_point_tilt(i))
|
||||
if not start_init:
|
||||
follow.set_offset(0.001)
|
||||
else:
|
||||
follow.set_offset(START_OFFSET[lane])
|
||||
start_init = false
|
||||
if get_road() != null:
|
||||
var road = get_road()
|
||||
var penalty_index = road.penalty_index(follow.get_offset(), current_speed)
|
||||
|
||||
if penalty_index >= 0:
|
||||
torque_penalty = road.get_torque_penalty(penalty_index)
|
||||
force_penalty = road.get_force_penalty(penalty_index)
|
||||
path_penalty = road.get_path_penalty(penalty_index)
|
||||
is_out = true
|
||||
is_resetable = false
|
||||
timer.start()
|
||||
|
||||
check_position()
|
||||
else:
|
||||
race_car.get_node("ray").set_enabled(false)
|
||||
if force_penalty.length() != 0:
|
||||
race_car.move_and_slide(force_penalty * current_speed + Vector3(0,-0.5,0))
|
||||
if torque_penalty.length() != 0:
|
||||
race_car.rotate_object_local(torque_penalty.normalized(), torque_penalty.length() * current_speed)
|
||||
if path_penalty > 0 && follow.get_offset() > 0.0:
|
||||
follow.set_offset(follow.get_offset() - 0.01)
|
||||
path_penalty -= 0.01
|
||||
current_speed -= 0.0002
|
||||
if current_speed < 0:
|
||||
current_speed = 0
|
||||
else:
|
||||
position = slave_position
|
||||
|
||||
|
||||
func get_road():
|
||||
return race_car.road
|
||||
|
||||
|
||||
func _on_raceCar_road_entered(road):
|
||||
|
||||
var prev_road = route.get_road(road.get_index()-1)
|
||||
if prev_road != null:
|
||||
prev_road.body.set_collision_layer_bit(get_index(),0)
|
||||
|
||||
buffered_curve = road.get_lane_curve(lane)
|
||||
|
||||
buffered_rotation = last_rotation
|
||||
|
||||
if path.curve.get_point_count() > 0:
|
||||
buffered_translate = Util.curve_get_last_point(path.curve)
|
||||
|
||||
if road.get_end_rotation().length() != 0:
|
||||
last_rotation += road.get_end_rotation()
|
||||
|
||||
has_next = true
|
||||
|
||||
|
||||
func get_player_name():
|
||||
return player_name
|
||||
|
||||
|
||||
func set_player_name(new_name):
|
||||
player_name = new_name
|
||||
|
||||
|
||||
func get_player_color():
|
||||
return player_color
|
||||
|
||||
|
||||
func set_player_color(new_color):
|
||||
player_color = new_color
|
||||
var material = SpatialMaterial.new()
|
||||
material.set_albedo(player_color)
|
||||
race_car.get_node("body").set_surface_material(1,material)
|
||||
|
||||
|
||||
remotesync func set_first(is_first:bool):
|
||||
if is_first:
|
||||
add_to_group("first")
|
||||
else:
|
||||
remove_from_group("first")
|
||||
|
||||
|
||||
master func check_position():
|
||||
position = Vector2(race_car.road_index, follow.get_offset())
|
||||
rset("slave_position", position)
|
||||
|
||||
|
||||
master func reset():
|
||||
if is_resetable:
|
||||
has_next = false
|
||||
current_speed = 0
|
||||
|
||||
var road = race_car.road
|
||||
road.body.set_collision_layer_bit(get_index(),1)
|
||||
|
||||
while road.reset_index != 0:
|
||||
road = route.get_road(road.get_index() - road.reset_index)
|
||||
road.body.set_collision_layer_bit(get_index(),1)
|
||||
|
||||
path.curve.clear_points()
|
||||
|
||||
force_penalty = Vector3(0,0,0)
|
||||
torque_penalty = Vector3(0,0,0)
|
||||
|
||||
buffered_translate = road.get_translation()
|
||||
last_rotation = road.get_rotation()
|
||||
|
||||
race_car.road_index = road.get_index()
|
||||
race_car.road = null
|
||||
race_car.collider = null
|
||||
race_car.transform = Transform()
|
||||
race_car.get_node("ray").set_enabled(true)
|
||||
|
||||
|
||||
follow.set_transform(road.get_transform())
|
||||
|
||||
is_out = false
|
||||
is_resetable = false
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
|
||||
func set_start(new_lane:int):
|
||||
lane = new_lane
|
||||
follow.set_h_offset(LANE_OFFSET[lane])
|
||||
|
||||
|
||||
func _on_ResetTimer_timeout():
|
||||
is_resetable = true
|
||||
@@ -0,0 +1,29 @@
|
||||
extends Spatial
|
||||
|
||||
var road_ray:RayCast
|
||||
var collider
|
||||
var road:Road
|
||||
var road_index:int = 0
|
||||
|
||||
puppet var slave_transform:Transform
|
||||
|
||||
signal road_entered(road)
|
||||
|
||||
|
||||
func _ready():
|
||||
road_ray = get_node("ray")
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_network_master():
|
||||
if road_ray.is_colliding():
|
||||
if road_ray.get_collider() != collider:
|
||||
var parent = road_ray.get_collider().get_parent()
|
||||
if parent is Road && (road == null && road_index == parent.get_index() || road.get_index() == parent.get_index() - 1) && !parent.is_preview():
|
||||
collider = road_ray.get_collider()
|
||||
road = parent
|
||||
road_index = road.get_index()
|
||||
emit_signal("road_entered",road)
|
||||
rset_unreliable("slave_transform", get_global_transform())
|
||||
else:
|
||||
set_global_transform(slave_transform)
|
||||
@@ -0,0 +1,139 @@
|
||||
extends MeshInstance
|
||||
|
||||
class_name Road
|
||||
|
||||
export var end_rotation:Vector3 = Vector3(0,0,0)
|
||||
|
||||
export var first_speed_factor:float = 1.0
|
||||
export var creator_speed_factor:float = 1.0
|
||||
export var chasers_speed_factor:float = 1.0
|
||||
|
||||
export var reset_index:int = 0
|
||||
|
||||
export (PoolVector3Array) var speed_constrains = PoolVector3Array()
|
||||
export (PoolVector3Array) var force_penalties = PoolVector3Array()
|
||||
export (PoolVector3Array) var torque_penalties = PoolVector3Array()
|
||||
export (Array,float) var path_penalties = []
|
||||
|
||||
var body:StaticBody
|
||||
|
||||
var creator:int = -1
|
||||
var preview:bool = false
|
||||
|
||||
|
||||
func _init():
|
||||
if not has_node("StaticBody"):
|
||||
body = StaticBody.new()
|
||||
body.set_name("StaticBody")
|
||||
var shape = CollisionShape.new()
|
||||
shape.set_name("CollisionShape")
|
||||
shape.shape = mesh.create_trimesh_shape()
|
||||
body.add_child(shape)
|
||||
body.set_collision_layer_bit(0,1)
|
||||
body.set_collision_layer_bit(1,1)
|
||||
body.set_collision_layer_bit(2,1)
|
||||
body.set_collision_layer_bit(3,1)
|
||||
add_child(body)
|
||||
else:
|
||||
body = get_node("StaticBody")
|
||||
|
||||
|
||||
func get_creator():
|
||||
return creator
|
||||
|
||||
|
||||
func set_creator(new_creator):
|
||||
creator = int(new_creator)
|
||||
|
||||
|
||||
func set_color(new_color):
|
||||
pass # TODO
|
||||
|
||||
|
||||
func get_path():
|
||||
return get_node("Path")
|
||||
|
||||
|
||||
func get_curve():
|
||||
return get_path().get_curve()
|
||||
|
||||
|
||||
func get_lane_curve(lane:int):
|
||||
if has_node("lanes"):
|
||||
return get_node("lanes").get_child(lane).get_curve()
|
||||
else:
|
||||
return get_path().get_curve()
|
||||
|
||||
|
||||
func get_end_rotation():
|
||||
return end_rotation
|
||||
|
||||
|
||||
func set_preview(prev):
|
||||
preview = prev
|
||||
if prev:
|
||||
set_material_override(SpatialMaterial.new())
|
||||
else:
|
||||
set_material_override(null)
|
||||
|
||||
|
||||
func is_preview():
|
||||
return preview
|
||||
|
||||
|
||||
func get_next_lane(lane):
|
||||
return lane
|
||||
|
||||
|
||||
func penalty_index(distance:float, speed:float):
|
||||
for index in range(speed_constrains.size()):
|
||||
var constrain = speed_constrains[index]
|
||||
if constrain.x <= distance && constrain.y >= distance:
|
||||
if constrain.z < 0 && speed < constrain.z * -1 || constrain.z > 0 && speed > constrain.z:
|
||||
return index
|
||||
return -1
|
||||
|
||||
|
||||
func get_torque_penalty(index:int):
|
||||
if index >= 0:
|
||||
if torque_penalties.size() < (index + 1):
|
||||
return get_torque_penalty(index - 1)
|
||||
if get_rotation().length() != 0:
|
||||
return torque_penalties[index].rotated(get_rotation().normalized(), get_rotation().length())
|
||||
else:
|
||||
return torque_penalties[index]
|
||||
return Vector3(0,0,0)
|
||||
|
||||
|
||||
func get_force_penalty(index:int):
|
||||
if index >= 0:
|
||||
if force_penalties.size() < (index + 1):
|
||||
return get_force_penalty(index - 1)
|
||||
if get_rotation().length() != 0:
|
||||
return force_penalties[index].rotated(get_rotation().normalized(), get_rotation().length())
|
||||
else:
|
||||
return force_penalties[index]
|
||||
|
||||
return Vector3(0,0,0)
|
||||
|
||||
|
||||
func get_path_penalty(index:int):
|
||||
if index >= 0:
|
||||
if path_penalties.size() < (index + 1):
|
||||
return get_path_penalty(index - 1)
|
||||
|
||||
return path_penalties[index]
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
func get_first_speed_factor():
|
||||
return first_speed_factor
|
||||
|
||||
|
||||
func get_creator_speed_factor():
|
||||
return creator_speed_factor
|
||||
|
||||
|
||||
func get_chasers_speed_factor():
|
||||
return chasers_speed_factor
|
||||
@@ -0,0 +1,33 @@
|
||||
extends Node
|
||||
|
||||
class_name TracksFactory
|
||||
|
||||
const START = "Start"
|
||||
const STRAIGHT = "StraightLong"
|
||||
const STRAIGHT_SMALL = "Straight"
|
||||
const CURVE_RIGHT = "CornerLarge"
|
||||
const CURVE_LEFT = "CornerLargeFlipped"
|
||||
const CURVE_LARGE_RIGHT = "CornerLarger"
|
||||
const CURVE_LARGE_LEFT = "CornerLargerFlipped"
|
||||
const CURVE_SMALL_RIGHT = "CornerSmall"
|
||||
const CURVE_SMALL_LEFT = "CornerSmallFlipped"
|
||||
const BUMP = "StraightLongBump"
|
||||
const BUMP_SMALL = "Bump"
|
||||
const SKEW_RIGHT = "StraightSkew"
|
||||
const SKEW_LEFT = "StraightSkewFlipped"
|
||||
const RAMP_UP = "RampLong"
|
||||
const RAMP_DOWN = "RampLongFlipped"
|
||||
const RAMP_CURVED_UP = "RampLongCurved"
|
||||
const RAMP_CURVED_DOWN = "RampLongCurvedFlipped"
|
||||
const RAMP_SMALL_UP = "Ramp"
|
||||
const RAMP_SMALL_DOWN = "RampFlipped"
|
||||
const CURVED_RIGHT = "CurvedFlipped"
|
||||
const CURVED_LEFT = "Curved"
|
||||
const LOOP = "Loop"
|
||||
|
||||
|
||||
func get_road_instance(road):
|
||||
var instance = load("res://scenes/road/road" + road + ".tscn").instance()
|
||||
if !instance.get_script():
|
||||
instance.set_script(load("res://scripts/road/road.gd"))
|
||||
return instance
|
||||
Reference in New Issue
Block a user