More more more
This commit is contained in:
parent
8673160466
commit
4849ba9c20
|
@ -3,4 +3,6 @@
|
|||
[ext_resource path="res://assets/fonts/iosevkalyte/iosevkalyte-regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
outline_size = 2
|
||||
outline_color = Color( 0, 0, 0, 1 )
|
||||
font_data = ExtResource( 1 )
|
||||
|
|
BIN
assets/img/Parallax80.png
Normal file
BIN
assets/img/Parallax80.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 350 KiB |
35
assets/img/Parallax80.png.import
Normal file
35
assets/img/Parallax80.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/Parallax80.png-fef98d95260a36330dc772bb5a676274.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/img/Parallax80.png"
|
||||
dest_files=[ "res://.import/Parallax80.png-fef98d95260a36330dc772bb5a676274.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
|
@ -1,9 +1,10 @@
|
|||
[gd_resource type="Theme" load_steps=7 format=2]
|
||||
[gd_resource type="Theme" load_steps=9 format=2]
|
||||
|
||||
[ext_resource path="res://assets/fonts/iosevkalyte/iosevkalyte.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://assets/img/panel.png" type="Texture" id=2]
|
||||
[ext_resource path="res://assets/ui/progressbar_stylebox.tres" type="StyleBox" id=3]
|
||||
|
||||
[sub_resource type="Image" id=5]
|
||||
[sub_resource type="Image" id=7]
|
||||
data = {
|
||||
"data": PoolByteArray( 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42 ),
|
||||
"format": "RGB8",
|
||||
|
@ -15,7 +16,7 @@ data = {
|
|||
[sub_resource type="ImageTexture" id=2]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 5 )
|
||||
image = SubResource( 7 )
|
||||
size = Vector2( 8, 8 )
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id=3]
|
||||
|
@ -34,7 +35,15 @@ margin_right = 4.0
|
|||
margin_top = 4.0
|
||||
margin_bottom = 4.0
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=6]
|
||||
corner_radius_top_left = 1
|
||||
corner_radius_top_right = 1
|
||||
corner_radius_bottom_right = 1
|
||||
corner_radius_bottom_left = 1
|
||||
|
||||
[resource]
|
||||
default_font = ExtResource( 1 )
|
||||
Panel/styles/panel = SubResource( 3 )
|
||||
PanelContainer/styles/panel = SubResource( 4 )
|
||||
ProgressBar/styles/bg = ExtResource( 3 )
|
||||
ProgressBar/styles/fg = SubResource( 6 )
|
||||
|
|
77
assets/tileset.tres
Normal file
77
assets/tileset.tres
Normal file
|
@ -0,0 +1,77 @@
|
|||
[gd_resource type="TileSet" load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://assets/img/spaced-dungeon-tileset.png" type="Texture" id=1]
|
||||
|
||||
[sub_resource type="NavigationPolygon" id=2]
|
||||
vertices = PoolVector2Array( 16, 16, 0, 16, 0, 0, 16, 0 )
|
||||
polygons = [ PoolIntArray( 0, 1, 2, 3 ) ]
|
||||
|
||||
[sub_resource type="ConvexPolygonShape2D" id=3]
|
||||
points = PoolVector2Array( 16, 16, 0, 16, 0, 0, 16, 0 )
|
||||
|
||||
[sub_resource type="OccluderPolygon2D" id=4]
|
||||
polygon = PoolVector2Array( 16, 16, 0, 16, 0, 0, 16, 0 )
|
||||
|
||||
[sub_resource type="ConvexPolygonShape2D" id=5]
|
||||
points = PoolVector2Array( 16, 16, 0, 16, 0, 0, 16, 0 )
|
||||
|
||||
[resource]
|
||||
resource_name = "dungeon"
|
||||
0/name = "spaced-dungeon-tileset.png 0"
|
||||
0/texture = ExtResource( 1 )
|
||||
0/tex_offset = Vector2( 0, 0 )
|
||||
0/modulate = Color( 1, 1, 1, 1 )
|
||||
0/region = Rect2( 0, 54, 16, 16 )
|
||||
0/tile_mode = 0
|
||||
0/occluder_offset = Vector2( 0, 0 )
|
||||
0/navigation_offset = Vector2( 0, 0 )
|
||||
0/navigation = SubResource( 2 )
|
||||
0/shape_offset = Vector2( 0, 0 )
|
||||
0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
|
||||
0/shape_one_way = false
|
||||
0/shape_one_way_margin = 0.0
|
||||
0/shapes = [ ]
|
||||
0/z_index = 0
|
||||
1/name = "spaced-dungeon-tileset.png 1"
|
||||
1/texture = ExtResource( 1 )
|
||||
1/tex_offset = Vector2( 0, 0 )
|
||||
1/modulate = Color( 1, 1, 1, 1 )
|
||||
1/region = Rect2( 36, 36, 16, 16 )
|
||||
1/tile_mode = 0
|
||||
1/occluder_offset = Vector2( 0, 0 )
|
||||
1/navigation_offset = Vector2( 0, 0 )
|
||||
1/shape_offset = Vector2( 0, 0 )
|
||||
1/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
|
||||
1/shape = SubResource( 3 )
|
||||
1/shape_one_way = false
|
||||
1/shape_one_way_margin = 1.0
|
||||
1/shapes = [ {
|
||||
"autotile_coord": Vector2( 0, 0 ),
|
||||
"one_way": false,
|
||||
"one_way_margin": 1.0,
|
||||
"shape": SubResource( 3 ),
|
||||
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
|
||||
} ]
|
||||
1/z_index = 0
|
||||
2/name = "spaced-dungeon-tileset.png 2"
|
||||
2/texture = ExtResource( 1 )
|
||||
2/tex_offset = Vector2( 0, 0 )
|
||||
2/modulate = Color( 1, 1, 1, 1 )
|
||||
2/region = Rect2( 36, 18, 16, 16 )
|
||||
2/tile_mode = 0
|
||||
2/occluder_offset = Vector2( 0, 0 )
|
||||
2/occluder = SubResource( 4 )
|
||||
2/navigation_offset = Vector2( 0, 0 )
|
||||
2/shape_offset = Vector2( 0, 0 )
|
||||
2/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
|
||||
2/shape = SubResource( 5 )
|
||||
2/shape_one_way = false
|
||||
2/shape_one_way_margin = 1.0
|
||||
2/shapes = [ {
|
||||
"autotile_coord": Vector2( 0, 0 ),
|
||||
"one_way": false,
|
||||
"one_way_margin": 1.0,
|
||||
"shape": SubResource( 5 ),
|
||||
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
|
||||
} ]
|
||||
2/z_index = 0
|
17
assets/ui/hp_bar_bg.tres
Normal file
17
assets/ui/hp_bar_bg.tres
Normal file
|
@ -0,0 +1,17 @@
|
|||
[gd_resource type="StyleBoxFlat" format=2]
|
||||
|
||||
[resource]
|
||||
content_margin_left = 0.0
|
||||
content_margin_right = 0.0
|
||||
content_margin_top = 0.0
|
||||
content_margin_bottom = 0.0
|
||||
bg_color = Color( 0.0666667, 0.0666667, 0.0666667, 1 )
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color( 1, 0.211765, 0, 1 )
|
||||
corner_radius_top_left = 1
|
||||
corner_radius_top_right = 1
|
||||
corner_radius_bottom_right = 1
|
||||
corner_radius_bottom_left = 1
|
17
assets/ui/hp_bar_fg.tres
Normal file
17
assets/ui/hp_bar_fg.tres
Normal file
|
@ -0,0 +1,17 @@
|
|||
[gd_resource type="StyleBoxFlat" format=2]
|
||||
|
||||
[resource]
|
||||
content_margin_left = 0.0
|
||||
content_margin_right = 0.0
|
||||
content_margin_top = 0.0
|
||||
content_margin_bottom = 0.0
|
||||
bg_color = Color( 1, 0.211765, 0, 1 )
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color( 1, 0.211765, 0, 1 )
|
||||
corner_radius_top_left = 1
|
||||
corner_radius_top_right = 1
|
||||
corner_radius_bottom_right = 1
|
||||
corner_radius_bottom_left = 1
|
17
assets/ui/mana_bar_bg.tres
Normal file
17
assets/ui/mana_bar_bg.tres
Normal file
|
@ -0,0 +1,17 @@
|
|||
[gd_resource type="StyleBoxFlat" format=2]
|
||||
|
||||
[resource]
|
||||
content_margin_left = 0.0
|
||||
content_margin_right = 0.0
|
||||
content_margin_top = 0.0
|
||||
content_margin_bottom = 0.0
|
||||
bg_color = Color( 0.0666667, 0.0666667, 0.0666667, 1 )
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color( 0, 0.309804, 1, 1 )
|
||||
corner_radius_top_left = 1
|
||||
corner_radius_top_right = 1
|
||||
corner_radius_bottom_right = 1
|
||||
corner_radius_bottom_left = 1
|
17
assets/ui/mana_bar_fg.tres
Normal file
17
assets/ui/mana_bar_fg.tres
Normal file
|
@ -0,0 +1,17 @@
|
|||
[gd_resource type="StyleBoxFlat" format=2]
|
||||
|
||||
[resource]
|
||||
content_margin_left = 0.0
|
||||
content_margin_right = 0.0
|
||||
content_margin_top = 0.0
|
||||
content_margin_bottom = 0.0
|
||||
bg_color = Color( 0, 0.309804, 1, 1 )
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color( 0, 0.309804, 1, 1 )
|
||||
corner_radius_top_left = 1
|
||||
corner_radius_top_right = 1
|
||||
corner_radius_bottom_right = 1
|
||||
corner_radius_bottom_left = 1
|
12
assets/ui/progressbar_stylebox.tres
Normal file
12
assets/ui/progressbar_stylebox.tres
Normal file
|
@ -0,0 +1,12 @@
|
|||
[gd_resource type="StyleBoxFlat" format=2]
|
||||
|
||||
[resource]
|
||||
bg_color = Color( 0.160784, 0.160784, 0.160784, 1 )
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
corner_radius_top_left = 1
|
||||
corner_radius_top_right = 1
|
||||
corner_radius_bottom_right = 1
|
||||
corner_radius_bottom_left = 1
|
|
@ -1,10 +1,30 @@
|
|||
[gd_scene format=2]
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://scripts/objects/bar.gd" type="Script" id=1]
|
||||
|
||||
[node name="bar" type="ProgressBar"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
value = 50.0
|
||||
percent_visible = false
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
label = NodePath("label")
|
||||
|
||||
[node name="label" type="Label" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -1024.0
|
||||
margin_bottom = -586.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 7
|
||||
align = 1
|
||||
valign = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[connection signal="resized" from="." to="." method="_on_bar_resized"]
|
||||
[connection signal="value_changed" from="." to="." method="_on_bar_value_changed"]
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
[gd_scene load_steps=18 format=2]
|
||||
[gd_scene load_steps=19 format=2]
|
||||
|
||||
[ext_resource path="res://assets/img/spaced-dungeon-tileset.png" type="Texture" id=1]
|
||||
[ext_resource path="res://assets/fonts/iosevkalyte/iosevkalyte-regular.ttf" type="DynamicFontData" id=2]
|
||||
[ext_resource path="res://assets/theme.tres" type="Theme" id=2]
|
||||
[ext_resource path="res://objects/bar.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://assets/ui/hp_bar_bg.tres" type="StyleBox" id=4]
|
||||
[ext_resource path="res://assets/ui/hp_bar_fg.tres" type="StyleBox" id=5]
|
||||
[ext_resource path="res://assets/ui/mana_bar_fg.tres" type="StyleBox" id=6]
|
||||
[ext_resource path="res://assets/ui/mana_bar_bg.tres" type="StyleBox" id=7]
|
||||
[ext_resource path="res://scripts/objects/player.gd" type="Script" id=10]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
|
@ -59,87 +63,95 @@ animations = [ {
|
|||
"speed": 5.0
|
||||
} ]
|
||||
|
||||
[sub_resource type="ConvexPolygonShape2D" id=11]
|
||||
points = PoolVector2Array( -2, 4, 2, 4, 6, 1, 6, -1, 1, -4, -1, -4, -6, -1, -6, 1 )
|
||||
|
||||
[sub_resource type="DynamicFont" id=13]
|
||||
size = 64
|
||||
font_data = ExtResource( 2 )
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=12]
|
||||
bg_color = Color( 0, 0.25098, 1, 1 )
|
||||
|
||||
[node name="player" type="KinematicBody2D" groups=["destructable"]]
|
||||
script = ExtResource( 10 )
|
||||
sprite = NodePath("sprite")
|
||||
collider = NodePath("collider")
|
||||
name_label = NodePath("ui/player_name")
|
||||
health_bar = NodePath("ui/c2/bars/health_bar")
|
||||
mana_bar = NodePath("ui/c2/bars/mana_bar")
|
||||
|
||||
[node name="sprite" type="AnimatedSprite" parent="."]
|
||||
modulate = Color( 0.384314, 0.796078, 1, 1 )
|
||||
position = Vector2( 0, -18 )
|
||||
position = Vector2( 0, -9 )
|
||||
scale = Vector2( 4, 4 )
|
||||
frames = SubResource( 10 )
|
||||
animation = "idle"
|
||||
frame = 1
|
||||
playing = true
|
||||
|
||||
[node name="collider" type="CollisionShape2D" parent="."]
|
||||
position = Vector2( 0, -6.5 )
|
||||
scale = Vector2( 1, 1.6 )
|
||||
shape = SubResource( 11 )
|
||||
[node name="collider" type="CollisionPolygon2D" parent="."]
|
||||
position = Vector2( 0, 39 )
|
||||
scale = Vector2( 4, 4 )
|
||||
polygon = PoolVector2Array( 6, -1, 6, 1, 1, 6, -1, 6, -6, 1, -6, -1, -1, -6, 1, -6 )
|
||||
|
||||
[node name="ui" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="c" type="CenterContainer" parent="ui"]
|
||||
margin_left = -50.0
|
||||
margin_top = 8.0
|
||||
margin_right = 350.0
|
||||
margin_bottom = 89.0
|
||||
[node name="ui" type="VBoxContainer" parent="."]
|
||||
modulate = Color( 1, 1, 1, 0.498039 )
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -59.0
|
||||
margin_top = -70.0
|
||||
margin_right = 61.0
|
||||
margin_bottom = 101.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
rect_scale = Vector2( 0.25, 0.25 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="player_name" type="Label" parent="ui/c"]
|
||||
visible = false
|
||||
margin_left = 24.0
|
||||
margin_right = 376.0
|
||||
margin_bottom = 81.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 7
|
||||
custom_fonts/font = SubResource( 13 )
|
||||
text = "player_name"
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
[node name="c2" type="CenterContainer" parent="ui"]
|
||||
margin_right = 120.0
|
||||
margin_bottom = 44.0
|
||||
size_flags_vertical = 0
|
||||
|
||||
[node name="bars" type="VBoxContainer" parent="."]
|
||||
margin_left = -18.0
|
||||
margin_top = -26.0
|
||||
margin_right = 18.0
|
||||
margin_bottom = -20.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
custom_constants/separation = 0
|
||||
[node name="bars" type="VBoxContainer" parent="ui/c2"]
|
||||
margin_right = 120.0
|
||||
margin_bottom = 44.0
|
||||
rect_min_size = Vector2( 120, 44 )
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
custom_constants/separation = 4
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="health_bar" parent="bars" instance=ExtResource( 3 )]
|
||||
[node name="health_bar" parent="ui/c2/bars" instance=ExtResource( 3 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 36.0
|
||||
margin_bottom = 3.0
|
||||
margin_right = 120.0
|
||||
margin_bottom = 20.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource( 2 )
|
||||
custom_styles/fg = ExtResource( 5 )
|
||||
custom_styles/bg = ExtResource( 4 )
|
||||
|
||||
[node name="mana_bar" parent="bars" instance=ExtResource( 3 )]
|
||||
[node name="mana_bar" parent="ui/c2/bars" instance=ExtResource( 3 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 3.0
|
||||
margin_right = 36.0
|
||||
margin_bottom = 6.0
|
||||
margin_top = 24.0
|
||||
margin_right = 120.0
|
||||
margin_bottom = 44.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
custom_styles/fg = SubResource( 12 )
|
||||
theme = ExtResource( 2 )
|
||||
custom_styles/fg = ExtResource( 6 )
|
||||
custom_styles/bg = ExtResource( 7 )
|
||||
max_value = 1000.0
|
||||
value = 600.0
|
||||
|
||||
[node name="player_name" type="Label" parent="ui"]
|
||||
margin_top = 48.0
|
||||
margin_right = 120.0
|
||||
margin_bottom = 171.0
|
||||
size_flags_horizontal = 7
|
||||
size_flags_vertical = 7
|
||||
text = "player_name"
|
||||
align = 1
|
||||
valign = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
|
61
objects/slime.tscn
Normal file
61
objects/slime.tscn
Normal file
|
@ -0,0 +1,61 @@
|
|||
[gd_scene load_steps=12 format=2]
|
||||
|
||||
[ext_resource path="res://assets/img/spaced-dungeon-tileset.png" type="Texture" id=1]
|
||||
[ext_resource path="res://scripts/objects/slime.gd" type="Script" id=2]
|
||||
[ext_resource path="res://scripts/objects/destructable.gd" type="Script" id=3]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 0, 432, 18, 36 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 18, 432, 18, 36 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 36, 432, 18, 36 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=4]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 54, 432, 18, 36 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=5]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 0, 432, 18, 36 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=6]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 0, 432, 18, 36 )
|
||||
|
||||
[sub_resource type="SpriteFrames" id=7]
|
||||
animations = [ {
|
||||
"frames": [ SubResource( 1 ), SubResource( 2 ), SubResource( 3 ), SubResource( 4 ), SubResource( 5 ), SubResource( 6 ) ],
|
||||
"loop": true,
|
||||
"name": "idle",
|
||||
"speed": 6.0
|
||||
} ]
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id=8]
|
||||
radius = 6.0
|
||||
height = 1.0
|
||||
|
||||
[node name="slime" type="KinematicBody2D"]
|
||||
scale = Vector2( 2, 2 )
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="sprite" type="AnimatedSprite" parent="."]
|
||||
scale = Vector2( 4, 4 )
|
||||
frames = SubResource( 7 )
|
||||
animation = "idle"
|
||||
frame = 3
|
||||
playing = true
|
||||
offset = Vector2( 1, -17 )
|
||||
|
||||
[node name="hurtbox" type="CollisionShape2D" parent="."]
|
||||
position = Vector2( 0, -26 )
|
||||
scale = Vector2( 4, 4 )
|
||||
shape = SubResource( 8 )
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[connection signal="die" from="hurtbox" to="." method="_on_hurtbox_die"]
|
|
@ -9,6 +9,11 @@
|
|||
config_version=4
|
||||
|
||||
_global_script_classes=[ {
|
||||
"base": "CollisionShape2D",
|
||||
"class": "Destructable",
|
||||
"language": "GDScript",
|
||||
"path": "res://scripts/objects/destructable.gd"
|
||||
}, {
|
||||
"base": "HBoxContainer",
|
||||
"class": "LobbyControl",
|
||||
"language": "GDScript",
|
||||
|
@ -20,6 +25,7 @@ _global_script_classes=[ {
|
|||
"path": "res://scripts/objects/peer.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
"Destructable": "",
|
||||
"LobbyControl": "",
|
||||
"PeerControl": ""
|
||||
}
|
||||
|
@ -28,12 +34,22 @@ _global_script_class_icons={
|
|||
|
||||
config/name="webrtc_tech_demo"
|
||||
run/main_scene="res://screens/main_menu.tscn"
|
||||
boot_splash/fullsize=false
|
||||
boot_splash/use_filter=false
|
||||
boot_splash/bg_color=Color( 0, 0, 0, 1 )
|
||||
config/icon="res://assets/img/icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
Global="*res://scripts/global/global.gd"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/width=1280
|
||||
window/size/height=720
|
||||
window/size/borderless=true
|
||||
window/dpi/allow_hidpi=true
|
||||
|
||||
[gdnative]
|
||||
|
||||
singletons=[ "res://webrtc/webrtc.tres" ]
|
||||
|
@ -79,6 +95,7 @@ common/enable_pause_aware_picking=true
|
|||
[rendering]
|
||||
|
||||
quality/driver/driver_name="GLES2"
|
||||
2d/snapping/use_gpu_pixel_snap=true
|
||||
vram_compression/import_etc=true
|
||||
vram_compression/import_etc2=false
|
||||
environment/default_clear_color=Color( 0, 0, 0, 1 )
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -23,16 +23,16 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="v" type="VBoxContainer" parent="."]
|
||||
margin_right = 984.0
|
||||
margin_bottom = 560.0
|
||||
margin_right = 1240.0
|
||||
margin_bottom = 680.0
|
||||
|
||||
[node name="h" type="HBoxContainer" parent="v"]
|
||||
margin_right = 984.0
|
||||
margin_right = 1240.0
|
||||
margin_bottom = 50.0
|
||||
alignment = 1
|
||||
|
||||
[node name="quit" type="Button" parent="v/h"]
|
||||
margin_right = 325.0
|
||||
margin_right = 410.0
|
||||
margin_bottom = 50.0
|
||||
rect_min_size = Vector2( 150, 50 )
|
||||
hint_tooltip = "Yeah, let's get out of here."
|
||||
|
@ -46,8 +46,8 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="multiplayer" type="Button" parent="v/h"]
|
||||
margin_left = 329.0
|
||||
margin_right = 654.0
|
||||
margin_left = 414.0
|
||||
margin_right = 825.0
|
||||
margin_bottom = 50.0
|
||||
rect_min_size = Vector2( 150, 50 )
|
||||
hint_tooltip = "This is what you came for!"
|
||||
|
@ -56,8 +56,8 @@ size_flags_vertical = 3
|
|||
text = "Multiplayer"
|
||||
|
||||
[node name="singleplayer" type="Button" parent="v/h"]
|
||||
margin_left = 658.0
|
||||
margin_right = 984.0
|
||||
margin_left = 829.0
|
||||
margin_right = 1240.0
|
||||
margin_bottom = 50.0
|
||||
rect_min_size = Vector2( 150, 50 )
|
||||
hint_tooltip = "This is a multiplayer tech demo, you dunce.
|
||||
|
@ -72,16 +72,16 @@ __meta__ = {
|
|||
|
||||
[node name="c" type="CenterContainer" parent="v"]
|
||||
margin_top = 54.0
|
||||
margin_right = 984.0
|
||||
margin_bottom = 560.0
|
||||
margin_right = 1240.0
|
||||
margin_bottom = 680.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="v" type="VBoxContainer" parent="v/c"]
|
||||
margin_left = 124.0
|
||||
margin_top = 150.0
|
||||
margin_right = 859.0
|
||||
margin_bottom = 356.0
|
||||
margin_left = 252.0
|
||||
margin_top = 210.0
|
||||
margin_right = 987.0
|
||||
margin_bottom = 416.0
|
||||
|
||||
[node name="title" type="Label" parent="v/c/v"]
|
||||
margin_right = 735.0
|
||||
|
|
|
@ -83,7 +83,11 @@ func singleplayer():
|
|||
webrtc = WebRTCMultiplayer.new()
|
||||
webrtc.initialize(1, false)
|
||||
get_tree().network_peer = webrtc
|
||||
_create_peer({id = 1})
|
||||
peers[1] = {
|
||||
connected = false,
|
||||
ready = false,
|
||||
name = display_name,
|
||||
}
|
||||
|
||||
func close():
|
||||
if webrtc != null: webrtc.close()
|
||||
|
@ -163,9 +167,28 @@ func _signaller_connected(protocol = ""):
|
|||
_send_json({name = display_name}, "init")
|
||||
|
||||
func _process(_delta: float):
|
||||
if webrtc:
|
||||
webrtc.poll()
|
||||
while webrtc.get_available_packet_count() > 0:
|
||||
print("WebRTC Packet: %s" % webrtc.get_packet().get_string_from_utf8())
|
||||
var status: int = websocket.get_connection_status()
|
||||
if status in [WebSocketClient.CONNECTION_CONNECTED, WebSocketClient.CONNECTION_CONNECTING]:
|
||||
websocket.poll()
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventKey:
|
||||
if event.pressed and event.scancode == KEY_D:
|
||||
print("## DEBUG NET INFO")
|
||||
for p in get_tree().get_network_connected_peers():
|
||||
var d = webrtc.get_peer(p)
|
||||
print("get_peer(%s): %s" % [p, d])
|
||||
for c in d.channels:
|
||||
print("Channel: %s" % c)
|
||||
if c:
|
||||
print("Label: %s, Protocol: %s, Negotiated: %s" % [c.get_label(), c.get_protocol(), "true" if c.is_negotiated() else "false"])
|
||||
else:
|
||||
print("Channel is null?")
|
||||
|
||||
|
||||
func _signaller_data():
|
||||
var msg: String = websocket.get_peer(1).get_packet().get_string_from_utf8()
|
||||
|
@ -212,19 +235,27 @@ func _process_signaller_message(data: Dictionary):
|
|||
|
||||
func _lobby_joined(lobby_data):
|
||||
current_lobby = lobby_data
|
||||
peers[int(lobby_data.id)] = {
|
||||
connected = true,
|
||||
ready = int(lobby_data.id) == 1,
|
||||
name = display_name,
|
||||
id = int(lobby_data.id),
|
||||
}
|
||||
print("Lobby Joined: %s" % lobby_data)
|
||||
emit_signal("lobby_joined", lobby_data)
|
||||
|
||||
func _lobby_left(uuid):
|
||||
current_lobby = null
|
||||
peers.erase(get_tree().get_network_unique_id())
|
||||
print("Lobby Left: %s" % uuid)
|
||||
emit_signal("lobby_left", uuid)
|
||||
_deinit_webrtc_peer()
|
||||
|
||||
func _create_peer(data):
|
||||
func _create_peer(data: Dictionary):
|
||||
var id = data.id
|
||||
if id == webrtc.get_unique_id(): return
|
||||
var peer: WebRTCPeerConnection = WebRTCPeerConnection.new()
|
||||
print("Creating WebRTC Peer %s" % [id])
|
||||
print("Creating WebRTC Peer: %s" % [data])
|
||||
peer.connect("session_description_created", self, "_webrtc_offer_created", [id])
|
||||
peer.connect("ice_candidate_created", self, "_new_ice_candidate", [id])
|
||||
peer.initialize({"iceServers": DEFAULT_ICE_SERVERS})
|
||||
|
@ -235,7 +266,7 @@ func _create_peer(data):
|
|||
peers[int(id)] = {
|
||||
connected = false,
|
||||
ready = false,
|
||||
name = "",
|
||||
name = data.name if data.has(name) else DEFAULT_DISPLAY_NAME,
|
||||
}
|
||||
emit_signal("peer_created", data)
|
||||
|
||||
|
|
15
scripts/objects/bar.gd
Normal file
15
scripts/objects/bar.gd
Normal file
|
@ -0,0 +1,15 @@
|
|||
extends ProgressBar
|
||||
|
||||
export(NodePath) onready var label = get_node(label) as Label
|
||||
|
||||
onready var font = label.get_theme_default_font()
|
||||
|
||||
func _ready():
|
||||
_on_bar_resized()
|
||||
|
||||
func _on_bar_value_changed(value):
|
||||
label.text = "%d / %d" % [value, max_value]
|
||||
|
||||
func _on_bar_resized():
|
||||
label.visible = rect_size.y > 16
|
||||
label.rect_size = rect_size / label.rect_scale
|
20
scripts/objects/destructable.gd
Normal file
20
scripts/objects/destructable.gd
Normal file
|
@ -0,0 +1,20 @@
|
|||
extends CollisionShape2D
|
||||
|
||||
class_name Destructable
|
||||
|
||||
signal hit(damage, collision)
|
||||
signal die(damage, collision)
|
||||
|
||||
export var max_health = 100
|
||||
export var health = 100
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func trigger_hit(damage, collision):
|
||||
emit_signal("hit", damage, collision)
|
||||
health = clamp(health - damage, -max_health, max_health)
|
||||
if health > max_health:
|
||||
health = max_health
|
||||
elif health <= 0:
|
||||
emit_signal("die", damage, collision)
|
|
@ -1,23 +1,26 @@
|
|||
extends KinematicBody2D
|
||||
|
||||
export var weight = 8
|
||||
export var max_speed = 80 # ~5 tiles/sec at top speed
|
||||
export var friction = 500
|
||||
export var speed = 20
|
||||
export var mana_per_sec = 10
|
||||
export var health_per_sec = 1
|
||||
export var health = 100 setget set_health
|
||||
export var max_health = 100 setget set_max_health
|
||||
export var mana = 50 setget set_mana
|
||||
export var max_mana = 1000 setget set_max_mana
|
||||
export(NodePath) onready var sprite = get_node(sprite) as AnimatedSprite
|
||||
export(NodePath) onready var collider = get_node(collider) as CollisionShape2D
|
||||
export(NodePath) onready var name_label = get_node(name_label) as Label
|
||||
export(NodePath) onready var health_bar = get_node(health_bar) as ProgressBar
|
||||
export(NodePath) onready var mana_bar = get_node(mana_bar) as ProgressBar
|
||||
|
||||
export var weight := 8
|
||||
export var max_speed := 64 * 5 # ~5 tiles/sec at top speed
|
||||
export var friction := 2000
|
||||
export var speed := 80
|
||||
export var mana_per_sec := 10
|
||||
export var health_per_sec := 1
|
||||
export var health := 100.0 setget set_health
|
||||
export var max_health := 100.0 setget set_max_health
|
||||
export var mana := 50.0 setget set_mana
|
||||
export var max_mana := 1000.0 setget set_max_mana
|
||||
|
||||
enum PlayerClass { WIZARD }
|
||||
|
||||
onready var viewport = get_viewport()
|
||||
onready var sprite = $sprite
|
||||
onready var collider = $collider
|
||||
onready var name_displayer = $ui/c/player_name
|
||||
onready var display_name = name
|
||||
onready var display_name = Global.client.DEFAULT_DISPLAY_NAME setget set_display_name
|
||||
onready var player_class = PlayerClass.WIZARD
|
||||
onready var skills = []
|
||||
|
||||
|
@ -44,47 +47,52 @@ onready var skills = []
|
|||
remotesync var acceleration = Vector2.ZERO
|
||||
remotesync var velocity = Vector2.ZERO
|
||||
|
||||
func set_health(x):
|
||||
func set_health(x: float):
|
||||
health = x
|
||||
$bars/health_bar.value = x
|
||||
maybe_hide_health_bar()
|
||||
update_bars()
|
||||
|
||||
func set_max_health(x):
|
||||
func set_max_health(x: float):
|
||||
max_health = x
|
||||
$bars/health_bar.max_value = x
|
||||
maybe_hide_health_bar()
|
||||
update_bars()
|
||||
|
||||
func set_mana(x):
|
||||
func set_mana(x: float):
|
||||
mana = x
|
||||
$bars/mana_bar.value = x
|
||||
maybe_hide_mana_bar()
|
||||
update_bars()
|
||||
|
||||
func set_max_mana(x):
|
||||
func set_max_mana(x: float):
|
||||
max_mana = x
|
||||
$bars/mana_bar.max_value = x
|
||||
maybe_hide_mana_bar()
|
||||
update_bars()
|
||||
|
||||
func maybe_hide_mana_bar():
|
||||
if mana >= max_mana:
|
||||
$bars/mana_bar.hide()
|
||||
else:
|
||||
$bars/mana_bar.show()
|
||||
func update_bars():
|
||||
if mana_bar is ProgressBar:
|
||||
mana_bar.max_value = max_mana
|
||||
mana_bar.value = mana
|
||||
if mana >= max_mana:
|
||||
mana_bar.hide()
|
||||
else:
|
||||
mana_bar.show()
|
||||
if health_bar is ProgressBar:
|
||||
health_bar.max_value = max_health
|
||||
health_bar.value = health
|
||||
if health >= max_health:
|
||||
health_bar.hide()
|
||||
else:
|
||||
health_bar.show()
|
||||
|
||||
func maybe_hide_health_bar():
|
||||
if health >= max_health:
|
||||
$bars/health_bar.hide()
|
||||
else:
|
||||
$bars/health_bar.show()
|
||||
|
||||
func _ready():
|
||||
# rset_config("acceleration", MultiplayerAPI.RPC_MODE_REMOTESYNC)
|
||||
# rset_config("velocity", MultiplayerAPI.RPC_MODE_REMOTESYNC)
|
||||
# rset_config("position", MultiplayerAPI.RPC_MODE_SLAVE)
|
||||
set_display_name(name)
|
||||
rset_config("position", MultiplayerAPI.RPC_MODE_SLAVE)
|
||||
var ns = get_tree().get_network_connected_peers().size()
|
||||
if ns < 1:
|
||||
print("Hiding Player Name %s..." % ns)
|
||||
name_label.hide()
|
||||
set_display_name(display_name)
|
||||
# if not is_network_master():
|
||||
# mana_bar.hi
|
||||
|
||||
|
||||
func set_display_name(i_name):
|
||||
display_name = i_name
|
||||
name_displayer.text = display_name
|
||||
if name_label is Label: name_label.text = display_name
|
||||
|
||||
static func int_input_action(actions) -> int:
|
||||
if typeof(actions) == TYPE_ARRAY:
|
||||
|
@ -96,12 +104,12 @@ static func int_input_action(actions) -> int:
|
|||
return int(Input.is_action_pressed(actions))
|
||||
|
||||
func _physics_process(delta):
|
||||
# if get_viewport().get_camera() != null: name_displayer.rect_scale = Vector2(get_viewport().get_camera().zoom)
|
||||
self.mana += (mana_per_sec*delta)
|
||||
self.health += (health_per_sec*delta)
|
||||
# if get_viewport().get_camera() != null: name_label.rect_scale = Vector2(get_viewport().get_camera().zoom)
|
||||
self.mana += mana_per_sec * delta
|
||||
self.health += health_per_sec * delta
|
||||
_process_input()
|
||||
_process_animation()
|
||||
rset("velocity", move_and_slide((velocity + acceleration).clamped(max_speed), Vector2.ZERO, false, 4, 0.785398, false).move_toward(Vector2.ZERO, friction * delta))
|
||||
rset_unreliable("velocity", move_and_slide((velocity + acceleration).clamped(max_speed), Vector2.ZERO, false, 4, 0.785398, false).move_toward(Vector2.ZERO, friction * delta))
|
||||
for index in get_slide_count():
|
||||
var collision = get_slide_collision(index)
|
||||
if collision.collider is RigidBody2D:
|
||||
|
@ -118,9 +126,11 @@ func _process_input():
|
|||
# key frame perfectly
|
||||
iv.x = int_input_action(["ui_right", "right"]) - int_input_action(["ui_left", "left"])
|
||||
iv.y = int_input_action(["ui_down", "down"]) - int_input_action(["ui_up", "up"])
|
||||
rset("acceleration", iv.normalized() * speed)
|
||||
rset_unreliable("acceleration", iv.normalized() * speed)
|
||||
rset_unreliable("position", position)
|
||||
|
||||
func _process_animation():
|
||||
if sprite == null: return
|
||||
if velocity == Vector2.ZERO:
|
||||
sprite.animation = "idle"
|
||||
else:
|
||||
|
|
60
scripts/objects/slime.gd
Normal file
60
scripts/objects/slime.gd
Normal file
|
@ -0,0 +1,60 @@
|
|||
extends KinematicBody2D
|
||||
|
||||
export var weight = 8
|
||||
export var max_speed = 48 # ~3 tiles/sec at top speed
|
||||
export var friction = 500
|
||||
export var speed = 20
|
||||
|
||||
var target_player = null
|
||||
remotesync var velocity = Vector2.ZERO
|
||||
remotesync var acceleration = Vector2.ZERO
|
||||
|
||||
enum {
|
||||
IDLE,
|
||||
WANDER,
|
||||
CHASE,
|
||||
ATTACK
|
||||
}
|
||||
|
||||
var state = IDLE
|
||||
|
||||
func _ready():
|
||||
rset_config("position", MultiplayerAPI.RPC_MODE_SLAVE)
|
||||
|
||||
func _physics_process(delta):
|
||||
match state:
|
||||
IDLE:
|
||||
if target_player != null:
|
||||
state = CHASE
|
||||
else:
|
||||
rset_unreliable("acceleration", Vector2.ZERO)
|
||||
WANDER:
|
||||
pass
|
||||
CHASE:
|
||||
if target_player == null:
|
||||
state = IDLE
|
||||
else:
|
||||
rset_unreliable("acceleration", (target_player.global_position - global_position).normalized() * speed)
|
||||
ATTACK:
|
||||
pass
|
||||
rset("velocity", move_and_slide((velocity + acceleration).clamped(max_speed), Vector2.ZERO, false, 4, 0.785398, false).move_toward(Vector2.ZERO, friction * delta))
|
||||
if velocity.x < 1:
|
||||
$sprite.flip_h = true
|
||||
elif velocity.x > 1:
|
||||
$sprite.flip_h = false
|
||||
|
||||
if is_network_master():
|
||||
rset_unreliable("position", position)
|
||||
|
||||
func seek_player():
|
||||
pass
|
||||
|
||||
func _on_hurtbox_die(_a, _b):
|
||||
print("slime die")
|
||||
rpc("die")
|
||||
|
||||
remotesync func die():
|
||||
queue_free()
|
||||
|
||||
func _on_hurtbox_hit():
|
||||
print("slime hit")
|
|
@ -1,8 +1,10 @@
|
|||
extends Node2D
|
||||
extends Control
|
||||
|
||||
onready var player_obj = preload("res://objects/player.tscn")
|
||||
|
||||
onready var camera = $camera
|
||||
export(NodePath) onready var camera = get_node(camera) as Camera2D
|
||||
export(NodePath) onready var menu = get_node(menu) as PopupDialog
|
||||
|
||||
onready var zoom_levels = [0.25, 0.5, 1, 1.5, 2, 2.5, 3]
|
||||
onready var current_zoom_level_index = 2
|
||||
onready var player = null
|
||||
|
@ -10,7 +12,8 @@ onready var players = null
|
|||
|
||||
func _ready():
|
||||
# TODO: probably have to wait for all peers to be ready before we add players
|
||||
camera.zoom = Vector2(0.25, 0.25)
|
||||
# camera.zoom = Vector2(0.25, 0.25)
|
||||
Global.client.connect("webrtc_peer_disconnected", self, "_webrtc_peer_disconnected")
|
||||
if Global.client.is_host():
|
||||
for id in get_tree().get_network_connected_peers():
|
||||
Global.client.peers[id].ready = false
|
||||
|
@ -25,25 +28,31 @@ remotesync func ready(id):
|
|||
for id in Global.client.peers: all_ready = all_ready and Global.client.peers[id].ready
|
||||
if all_ready: start()
|
||||
|
||||
func _webrtc_peer_disconnected(id):
|
||||
if Global.client.peers[id].has("player"):
|
||||
Global.client.peers[id].player.queue_free()
|
||||
|
||||
func start():
|
||||
print("Starting Game...")
|
||||
# for each peer
|
||||
for id in get_tree().get_network_connected_peers():
|
||||
print("Creating player for peer %d" % id)
|
||||
rpc("add_player", id)
|
||||
rpc("add_player", 1)
|
||||
for id in Global.client.peers:
|
||||
print("Creating player for peer %d (name: %s)" % [id, Global.client.peers[id].name])
|
||||
rpc("add_player", id, Global.client.peers[id].name)
|
||||
|
||||
func _process(_delta):
|
||||
if player: camera.offset = player.position
|
||||
|
||||
remotesync func add_player(id):
|
||||
remotesync func add_player(id, name):
|
||||
var new_player = player_obj.instance()
|
||||
if id == get_tree().get_network_unique_id(): player = new_player
|
||||
new_player.name = Global.client.peers[id].name
|
||||
new_player.name = str(id)
|
||||
new_player.set_network_master(id)
|
||||
add_child(new_player)
|
||||
new_player.global_position = Vector2(-100 + (id % 200), -100 + (id % 200))
|
||||
print("Added player: %s for peer %s" % [new_player, id])
|
||||
new_player.global_position = Vector2(-400 + (id % 800), -400 + (id % 800))
|
||||
print("Added player: %s for peer %s named %s" % [new_player, id, name])
|
||||
Global.client.peers[id].player = new_player
|
||||
new_player.display_name = name
|
||||
|
||||
func _on_Button_pressed():
|
||||
Global.main_menu()
|
||||
func _on_leave_pressed(): Global.main_menu()
|
||||
func _on_menu_button_pressed(): menu.popup_centered()
|
||||
func _on_close_pressed(): menu.hide()
|
||||
|
|
|
@ -40,6 +40,12 @@ func _signaller_disconnected():
|
|||
func _lobby_joined(data):
|
||||
add_chat("# Connected to %s" % data.name)
|
||||
_update_ui()
|
||||
_add_peer(data.id, {
|
||||
connected = true,
|
||||
ready = int(data.id) == 1,
|
||||
name = Global.client.display_name,
|
||||
id = int(data.id),
|
||||
})
|
||||
Global.client.request_peer_list()
|
||||
|
||||
func _webrtc_connection_succeeded():
|
||||
|
|
Loading…
Reference in a new issue