Compare commits
35 Commits
03421264fd
...
main
Author | SHA1 | Date | |
---|---|---|---|
322cdf1a05 | |||
ff92434409 | |||
4bd1d6bc9c | |||
041343a183 | |||
1e5f6990ad | |||
1132015349 | |||
16be17ba73 | |||
9747bf4d61 | |||
cda4b47ae9 | |||
cb48515d69 | |||
12ed20c26c | |||
70c07a5e90 | |||
d2bbeb45dc | |||
4c56d6badc | |||
607973c2ac | |||
43a63dbe91 | |||
3a5d90e50a | |||
c2841fbf0c | |||
1853c62699 | |||
89a1b54037 | |||
583f844bac | |||
211ef3bbc7 | |||
71b6d2617c | |||
52ced9c530 | |||
a02c118ced | |||
14d2399163 | |||
5a4e09d6d1 | |||
0747307cb3 | |||
e0e8b6bf71 | |||
ea5ddbd4aa | |||
99d95402c1 | |||
cb07298c8a | |||
21ba71373c | |||
1a5889bc7a | |||
1b60c7a3a7 |
BIN
assets/coin.png
Normal file
BIN
assets/coin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
35
assets/coin.png.import
Normal file
35
assets/coin.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dgo2frvws2o6f"
|
||||||
|
path.s3tc="res://.godot/imported/coin.png-f04b9cd408b88aba3ab0966b4da32df0.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/coin.png"
|
||||||
|
dest_files=["res://.godot/imported/coin.png-f04b9cd408b88aba3ab0966b4da32df0.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
BIN
assets/coin_flower.png
Normal file
BIN
assets/coin_flower.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 967 B |
35
assets/coin_flower.png.import
Normal file
35
assets/coin_flower.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dw3x3h3f34sy3"
|
||||||
|
path.bptc="res://.godot/imported/coin_flower.png-f7e515b96b6729484a68167e84f6e510.bptc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/coin_flower.png"
|
||||||
|
dest_files=["res://.godot/imported/coin_flower.png-f7e515b96b6729484a68167e84f6e510.bptc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=true
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
BIN
assets/musics/mod118.ogg
Normal file
BIN
assets/musics/mod118.ogg
Normal file
Binary file not shown.
19
assets/musics/mod118.ogg.import
Normal file
19
assets/musics/mod118.ogg.import
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="oggvorbisstr"
|
||||||
|
type="AudioStreamOggVorbis"
|
||||||
|
uid="uid://bpmc2amg1kbfn"
|
||||||
|
path="res://.godot/imported/mod118.ogg-227f261feb0690e0a8437a6b7afc3fd3.oggvorbisstr"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/musics/mod118.ogg"
|
||||||
|
dest_files=["res://.godot/imported/mod118.ogg-227f261feb0690e0a8437a6b7afc3fd3.oggvorbisstr"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
BIN
assets/musics/mod147-medley.mp3
Executable file
BIN
assets/musics/mod147-medley.mp3
Executable file
Binary file not shown.
19
assets/musics/mod147-medley.mp3.import
Normal file
19
assets/musics/mod147-medley.mp3.import
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="mp3"
|
||||||
|
type="AudioStreamMP3"
|
||||||
|
uid="uid://bknhw0jfylh6n"
|
||||||
|
path="res://.godot/imported/mod147-medley.mp3-a64644be0457748ff3a2c3e975df9f1d.mp3str"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/musics/mod147-medley.mp3"
|
||||||
|
dest_files=["res://.godot/imported/mod147-medley.mp3-a64644be0457748ff3a2c3e975df9f1d.mp3str"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
BIN
assets/musics/mod170-toomanyfuckingdoors.ogg
Executable file
BIN
assets/musics/mod170-toomanyfuckingdoors.ogg
Executable file
Binary file not shown.
19
assets/musics/mod170-toomanyfuckingdoors.ogg.import
Normal file
19
assets/musics/mod170-toomanyfuckingdoors.ogg.import
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="oggvorbisstr"
|
||||||
|
type="AudioStreamOggVorbis"
|
||||||
|
uid="uid://cgv0sm3h1cttu"
|
||||||
|
path="res://.godot/imported/mod170-toomanyfuckingdoors.ogg-c8c00bb4ac61939e013e8ce6fcf5df96.oggvorbisstr"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/musics/mod170-toomanyfuckingdoors.ogg"
|
||||||
|
dest_files=["res://.godot/imported/mod170-toomanyfuckingdoors.ogg-c8c00bb4ac61939e013e8ce6fcf5df96.oggvorbisstr"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
BIN
assets/musics/sho.ogg
Executable file
BIN
assets/musics/sho.ogg
Executable file
Binary file not shown.
19
assets/musics/sho.ogg.import
Normal file
19
assets/musics/sho.ogg.import
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="oggvorbisstr"
|
||||||
|
type="AudioStreamOggVorbis"
|
||||||
|
uid="uid://bxlatcfn5q4ty"
|
||||||
|
path="res://.godot/imported/sho.ogg-b66af2140d9acc6f3e75264b00966446.oggvorbisstr"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/musics/sho.ogg"
|
||||||
|
dest_files=["res://.godot/imported/sho.ogg-b66af2140d9acc6f3e75264b00966446.oggvorbisstr"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
2
assets/sfx/LICENSES
Normal file
2
assets/sfx/LICENSES
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
land.wav - https://opengameart.org/content/3-item-sounds - CC-BY 3.0
|
||||||
|
coinsplash.ogg - https://opengameart.org/content/coin-splash - No Rights Reserved
|
BIN
assets/sfx/coinsplash.ogg
Normal file
BIN
assets/sfx/coinsplash.ogg
Normal file
Binary file not shown.
19
assets/sfx/coinsplash.ogg.import
Normal file
19
assets/sfx/coinsplash.ogg.import
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="oggvorbisstr"
|
||||||
|
type="AudioStreamOggVorbis"
|
||||||
|
uid="uid://dkxv7wbq8s1gs"
|
||||||
|
path="res://.godot/imported/coinsplash.ogg-f4cc7a136a244c66d0c3ed8863b3a3e6.oggvorbisstr"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sfx/coinsplash.ogg"
|
||||||
|
dest_files=["res://.godot/imported/coinsplash.ogg-f4cc7a136a244c66d0c3ed8863b3a3e6.oggvorbisstr"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
BIN
assets/sfx/land.wav
Normal file
BIN
assets/sfx/land.wav
Normal file
Binary file not shown.
24
assets/sfx/land.wav.import
Normal file
24
assets/sfx/land.wav.import
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://dy3ngeohp1uqf"
|
||||||
|
path="res://.godot/imported/land.wav-6f339f0cb8abb44d119c317df4f4b636.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sfx/land.wav"
|
||||||
|
dest_files=["res://.godot/imported/land.wav-6f339f0cb8abb44d119c317df4f4b636.sample"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
force/8_bit=false
|
||||||
|
force/mono=false
|
||||||
|
force/max_rate=false
|
||||||
|
force/max_rate_hz=44100
|
||||||
|
edit/trim=false
|
||||||
|
edit/normalize=false
|
||||||
|
edit/loop_mode=0
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=0
|
32
assets/shaders/interactivity_outline2.gdshader
Normal file
32
assets/shaders/interactivity_outline2.gdshader
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
|
||||||
|
|
||||||
|
uniform float width : hint_range(0.0, 16.0);
|
||||||
|
uniform vec4 outline_color : source_color;
|
||||||
|
uniform sampler2D albedo_texture : source_color, filter_nearest;
|
||||||
|
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], vec4(0, 1, 0, 0), INV_VIEW_MATRIX[2], MODEL_MATRIX[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* thanks gdquest */
|
||||||
|
void fragment() {
|
||||||
|
vec2 size = vec2(width) / vec2(textureSize(albedo_texture, 0));
|
||||||
|
|
||||||
|
vec4 sprite_color = texture(albedo_texture, UV);
|
||||||
|
|
||||||
|
float alpha = sprite_color.a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(0.0, -size.y)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(size.x, -size.y)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(size.x, 0.0)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(size.x, size.y)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(0.0, size.y)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(-size.x, size.y)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(-size.x, 0.0)).a;
|
||||||
|
alpha += texture(albedo_texture, UV + vec2(-size.x, -size.y)).a;
|
||||||
|
|
||||||
|
vec3 final_color = mix(outline_color.rgb, sprite_color.rgb, sprite_color.a);
|
||||||
|
ALBEDO = final_color;
|
||||||
|
ALPHA = clamp(alpha, 0.0, 1.0);
|
||||||
|
}
|
BIN
assets/water-bomb.glb
Normal file
BIN
assets/water-bomb.glb
Normal file
Binary file not shown.
47
assets/water-bomb.glb.import
Normal file
47
assets/water-bomb.glb.import
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://ba2mut58elwrh"
|
||||||
|
path="res://.godot/imported/water-bomb.glb-e8fb14ce8e64d9818172ffab6efe431a.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/water-bomb.glb"
|
||||||
|
dest_files=["res://.godot/imported/water-bomb.glb-e8fb14ce8e64d9818172ffab6efe431a.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=0.2
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
_subresources={
|
||||||
|
"materials": {
|
||||||
|
"Sphere": {
|
||||||
|
"use_external/enabled": true,
|
||||||
|
"use_external/path": "res://assets/water_bomb_sphere_mat.tres"
|
||||||
|
},
|
||||||
|
"Top": {
|
||||||
|
"use_external/enabled": true,
|
||||||
|
"use_external/path": "res://assets/water_bomb_top_mat.tres"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gltf/naming_version=1
|
||||||
|
gltf/embedded_image_handling=1
|
16
assets/water_bomb_sphere_mat.tres
Normal file
16
assets/water_bomb_sphere_mat.tres
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://ruycqsmlhsiw"]
|
||||||
|
|
||||||
|
[ext_resource type="Shader" path="res://assets/shaders/interactivity_outline.gdshader" id="1_nmq18"]
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_gi5rt"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("1_nmq18")
|
||||||
|
shader_parameter/color = Color(1, 1, 1, 0)
|
||||||
|
shader_parameter/size = 1.24
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
next_pass = SubResource("ShaderMaterial_gi5rt")
|
||||||
|
albedo_color = Color(0.0936238, 0.825356, 1, 1)
|
||||||
|
metallic = 0.8
|
||||||
|
roughness = 0.4
|
16
assets/water_bomb_top_mat.tres
Normal file
16
assets/water_bomb_top_mat.tres
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://cm6b807gcxn4w"]
|
||||||
|
|
||||||
|
[ext_resource type="Shader" path="res://assets/shaders/interactivity_outline.gdshader" id="1_wfrf5"]
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_phi16"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("1_wfrf5")
|
||||||
|
shader_parameter/color = Color(1, 1, 1, 0)
|
||||||
|
shader_parameter/size = 1.24
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
next_pass = SubResource("ShaderMaterial_phi16")
|
||||||
|
albedo_color = Color(0.207843, 0.211765, 0.8, 1)
|
||||||
|
metallic = 0.2
|
||||||
|
roughness = 0.5
|
13
data/coin.tres
Normal file
13
data/coin.tres
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[gd_resource type="Resource" script_class="InventoryItem" load_steps=3 format=3 uid="uid://dbxrlw5ggh67j"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cb6qv3c0iojfl" path="res://icon.svg" id="1_eakc4"]
|
||||||
|
[ext_resource type="Script" path="res://src/lib/inventory_item.gd" id="2_lrh23"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("2_lrh23")
|
||||||
|
icon = ExtResource("1_eakc4")
|
||||||
|
name = "Coin"
|
||||||
|
id = &"coin"
|
||||||
|
stackable = true
|
||||||
|
stack_limit = 100
|
||||||
|
sells_for = 1
|
13
data/coin_flower.tres
Normal file
13
data/coin_flower.tres
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[gd_resource type="Resource" script_class="InventoryItem" load_steps=3 format=3 uid="uid://nrpcuqveh7io"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dw3x3h3f34sy3" path="res://assets/coin_flower.png" id="1_vrj0d"]
|
||||||
|
[ext_resource type="Script" path="res://src/lib/inventory_item.gd" id="3_fe16f"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("3_fe16f")
|
||||||
|
icon = ExtResource("1_vrj0d")
|
||||||
|
name = "Coin Flower"
|
||||||
|
id = &"coin_flower"
|
||||||
|
stackable = true
|
||||||
|
stack_limit = 9
|
||||||
|
sells_for = 2
|
11
data/meat.tres
Normal file
11
data/meat.tres
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[gd_resource type="Resource" script_class="InventoryItem" load_steps=3 format=3 uid="uid://cbbclpp04ptlf"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cb6qv3c0iojfl" path="res://icon.svg" id="1_2wt7x"]
|
||||||
|
[ext_resource type="Script" path="res://src/lib/inventory_item.gd" id="2_inc63"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("2_inc63")
|
||||||
|
icon = ExtResource("1_2wt7x")
|
||||||
|
name = "Meat"
|
||||||
|
id = &"meat"
|
||||||
|
count = 0
|
17
data/water_bomb.tres
Normal file
17
data/water_bomb.tres
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[gd_resource type="Resource" script_class="InventoryItem" load_steps=5 format=3 uid="uid://cmeif37pci2ek"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cb6qv3c0iojfl" path="res://icon.svg" id="1_g8c3q"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="1_t62t2"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ba2mut58elwrh" path="res://assets/water-bomb.glb" id="2_5cxkh"]
|
||||||
|
[ext_resource type="Script" path="res://src/lib/inventory_item.gd" id="2_pe2p8"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("2_pe2p8")
|
||||||
|
icon = ExtResource("1_g8c3q")
|
||||||
|
model = ExtResource("2_5cxkh")
|
||||||
|
bomb = ExtResource("1_t62t2")
|
||||||
|
name = "Water Bomb"
|
||||||
|
id = &"water_bomb"
|
||||||
|
stackable = false
|
||||||
|
stack_limit = 8
|
||||||
|
sells_for = 0
|
@ -1,10 +1,15 @@
|
|||||||
[gd_resource type="AudioBusLayout" format=3 uid="uid://dcxpomrfumov"]
|
[gd_resource type="AudioBusLayout" format=3 uid="uid://dcxpomrfumov"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
bus/0/volume_db = -8.00903
|
bus/1/name = &"Music"
|
||||||
bus/1/name = &"SoundEffects"
|
|
||||||
bus/1/solo = false
|
bus/1/solo = false
|
||||||
bus/1/mute = false
|
bus/1/mute = false
|
||||||
bus/1/bypass_fx = false
|
bus/1/bypass_fx = false
|
||||||
bus/1/volume_db = 0.0
|
bus/1/volume_db = -4.25003
|
||||||
bus/1/send = &"Master"
|
bus/1/send = &"Master"
|
||||||
|
bus/2/name = &"SoundEffects"
|
||||||
|
bus/2/solo = false
|
||||||
|
bus/2/mute = false
|
||||||
|
bus/2/bypass_fx = false
|
||||||
|
bus/2/volume_db = -10.0692
|
||||||
|
bus/2/send = &"Master"
|
||||||
|
@ -28,6 +28,7 @@ window/stretch/aspect="expand"
|
|||||||
|
|
||||||
spawn_points=""
|
spawn_points=""
|
||||||
voids=""
|
voids=""
|
||||||
|
sell_boxes=""
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
[gd_scene load_steps=4 format=3 uid="uid://s2a1pry5fw8f"]
|
|
||||||
|
|
||||||
[ext_resource type="Shader" path="res://scenes/interactivity_outline.gdshader" id="1_m18kw"]
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_gi5rt"]
|
|
||||||
resource_local_to_scene = true
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("1_m18kw")
|
|
||||||
shader_parameter/color = Color(1, 1, 1, 0)
|
|
||||||
shader_parameter/size = 1.24
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ptaep"]
|
|
||||||
resource_local_to_scene = true
|
|
||||||
next_pass = SubResource("ShaderMaterial_gi5rt")
|
|
||||||
albedo_color = Color(0.0936238, 0.825356, 1, 1)
|
|
||||||
metallic = 0.8
|
|
||||||
roughness = 0.4
|
|
||||||
|
|
||||||
[node name="Model" type="CSGSphere3D"]
|
|
||||||
material_override = SubResource("StandardMaterial3D_ptaep")
|
|
||||||
radius = 0.2
|
|
||||||
radial_segments = 24
|
|
||||||
rings = 12
|
|
158
src/ingame/bomb.gd
Normal file
158
src/ingame/bomb.gd
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
class_name Bomb extends Node3D
|
||||||
|
|
||||||
|
# TODO: have those in item db instead ?
|
||||||
|
@export var _splash_small_sound: AudioStreamPlayer3D
|
||||||
|
@export var _splash_small_quiet_sound: AudioStreamPlayer3D
|
||||||
|
@export var _sell_sound: AudioStreamPlayer3D
|
||||||
|
@export var _model: Node3D
|
||||||
|
@export var _splash_particles: GPUParticles3D
|
||||||
|
@export var _sell_particles: GPUParticles3D
|
||||||
|
@export var _picking_area: Area3D
|
||||||
|
@export var body: RigidBody3D
|
||||||
|
@export var billboard := false
|
||||||
|
|
||||||
|
## Initials to construct from
|
||||||
|
@export var item_id := &"ID"
|
||||||
|
@export var item_count := 0
|
||||||
|
|
||||||
|
## Will be constructed as { item_id, item_count }, but could be edited after
|
||||||
|
## Use set_item_bundle() if it's dynamically assigned, after adding to the scene
|
||||||
|
@export var item_bundle: Dictionary
|
||||||
|
|
||||||
|
## Effect of splhashing.
|
||||||
|
@export_enum("none", "water") var splash_function := "none"
|
||||||
|
|
||||||
|
## no longer exists and shouldn't be considered, but not ready to be freed yet
|
||||||
|
var is_dead := false
|
||||||
|
|
||||||
|
## something to ignore
|
||||||
|
var sender_id: int
|
||||||
|
var sender_body: PhysicsBody3D
|
||||||
|
|
||||||
|
var _in_splash_range := {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
body.process_mode = Node.PROCESS_MODE_DISABLED
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
if item_bundle.is_empty():
|
||||||
|
item_bundle = {
|
||||||
|
"item_id": item_id,
|
||||||
|
"count": item_count
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func set_item_bundle(p_item_bundle: Dictionary) -> void:
|
||||||
|
item_bundle = p_item_bundle
|
||||||
|
if _model.has_method("reflect_bundle"):
|
||||||
|
_model.reflect_bundle(item_bundle)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
# spin around, no need to replicate this
|
||||||
|
if not billboard:
|
||||||
|
_model.basis = _model.basis.rotated(Vector3(1, 0, 0), -((TAU*2) * delta))
|
||||||
|
_model.basis = _model.basis.orthonormalized()
|
||||||
|
|
||||||
|
if not is_multiplayer_authority():
|
||||||
|
return
|
||||||
|
|
||||||
|
# TODO: interpolate for non-authority clients
|
||||||
|
# or, do we *really* care about synchronicity? could simulate it independently.
|
||||||
|
global_position = body.global_position
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func _disable_body() -> void:
|
||||||
|
# not using synchronizer for this because it ends up enabling processing
|
||||||
|
# on other clients
|
||||||
|
(func() -> void: body.process_mode = Node.PROCESS_MODE_DISABLED).call_deferred()
|
||||||
|
_picking_area.collision_layer = 0
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_entered(p_body: Node3D) -> void:
|
||||||
|
if p_body == sender_body:
|
||||||
|
return
|
||||||
|
|
||||||
|
if p_body.is_in_group("voids"):
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
if p_body.is_in_group("sell_boxes"):
|
||||||
|
var item := GameState.fetch().INVENTORY_ITEM_DB[item_bundle["item_id"]] as InventoryItem
|
||||||
|
if item.sells_for != 0:
|
||||||
|
get_node("/root/Main").add_inventory_item.rpc(&"coin", item.sells_for * item_bundle["count"])
|
||||||
|
if _sell_sound != null:
|
||||||
|
_sell_sound.play()
|
||||||
|
if _sell_particles != null:
|
||||||
|
_sell_particles.amount = item.sells_for * item_bundle["count"]
|
||||||
|
_sell_particles.emitting = true
|
||||||
|
is_dead = true
|
||||||
|
_model.hide()
|
||||||
|
_disable_body.rpc()
|
||||||
|
await _sell_particles.finished
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
if splash_function == "water":
|
||||||
|
for area: Area3D in _in_splash_range:
|
||||||
|
area.get_parent_node_3d().water.rpc_id(1, sender_id)
|
||||||
|
|
||||||
|
if _splash_small_sound != null and sender_id != 0:
|
||||||
|
_splash_small_sound.play()
|
||||||
|
if _splash_small_quiet_sound:
|
||||||
|
_splash_small_quiet_sound.play()
|
||||||
|
if _splash_particles:
|
||||||
|
_splash_particles.emitting = true
|
||||||
|
|
||||||
|
is_dead = true
|
||||||
|
_model.hide()
|
||||||
|
_disable_body.rpc()
|
||||||
|
|
||||||
|
if _splash_small_sound != null and sender_id != 0:
|
||||||
|
await _splash_small_sound.finished
|
||||||
|
if _splash_small_quiet_sound != null and _splash_small_quiet_sound.playing:
|
||||||
|
await _splash_small_quiet_sound.finished
|
||||||
|
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_splash_area_entered(area: Area3D) -> void:
|
||||||
|
_in_splash_range[area] = true
|
||||||
|
|
||||||
|
|
||||||
|
func _on_splash_area_exited(area: Area3D) -> void:
|
||||||
|
_in_splash_range.erase(area)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func set_global_pos(new: Vector3) -> void:
|
||||||
|
global_position = new
|
||||||
|
body.global_position = new
|
||||||
|
body.reset_physics_interpolation()
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func get_picked_up() -> void:
|
||||||
|
if is_multiplayer_authority():
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func mark_interactive() -> void:
|
||||||
|
# TODO: whatever
|
||||||
|
if _model.scene_file_path == "res://assets/water-bomb.glb":
|
||||||
|
for submodel in _model.get_children():
|
||||||
|
(submodel as MeshInstance3D).mesh.surface_get_material(0).next_pass.set("shader_parameter/color", Color.WHITE)
|
||||||
|
elif _model.scene_file_path == "res://src/ingame/quad_viewmodel.tscn":
|
||||||
|
_model.mesh.material_override.set("shader_parameter/outline_color", Color.WHITE)
|
||||||
|
|
||||||
|
|
||||||
|
func mark_non_interactive() -> void:
|
||||||
|
if _model.scene_file_path == "res://assets/water-bomb.glb":
|
||||||
|
for submodel in _model.get_children():
|
||||||
|
(submodel as MeshInstance3D).mesh.surface_get_material(0).next_pass.set("shader_parameter/color", Color(1, 1, 1, 0))
|
||||||
|
elif _model.scene_file_path == "res://src/ingame/quad_viewmodel.tscn":
|
||||||
|
_model.mesh.material_override.set("shader_parameter/outline_color", Color.BLACK)
|
@ -2,6 +2,7 @@ extends Node3D
|
|||||||
|
|
||||||
@export var _player_scene: PackedScene
|
@export var _player_scene: PackedScene
|
||||||
|
|
||||||
|
@export var _soundtrack: AudioStreamPlayer
|
||||||
@export var _players: Node3D
|
@export var _players: Node3D
|
||||||
@export var _chat_panel: Panel
|
@export var _chat_panel: Panel
|
||||||
@export var _chat_input: LineEdit
|
@export var _chat_input: LineEdit
|
||||||
@ -10,6 +11,16 @@ extends Node3D
|
|||||||
@export var _chat_panel_inactive: Panel
|
@export var _chat_panel_inactive: Panel
|
||||||
@export var _chat_history_inactive: VBoxContainer
|
@export var _chat_history_inactive: VBoxContainer
|
||||||
@export var _chat_history_scroll_inactive: ScrollContainer
|
@export var _chat_history_scroll_inactive: ScrollContainer
|
||||||
|
@export var _coin_label: RichTextLabel
|
||||||
|
|
||||||
|
## Things to yet play, so to not repeat ourselves much.
|
||||||
|
const PLAYLIST: Array[String] = [
|
||||||
|
"res://assets/musics/mod118.ogg",
|
||||||
|
"res://assets/musics/mod147-medley.mp3",
|
||||||
|
"res://assets/musics/mod170-toomanyfuckingdoors.ogg",
|
||||||
|
"res://assets/musics/sho.ogg",
|
||||||
|
]
|
||||||
|
var _playlist_remaining: Array[String]
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -39,6 +50,19 @@ func _ready() -> void:
|
|||||||
if not OS.has_feature("dedicated_server"):
|
if not OS.has_feature("dedicated_server"):
|
||||||
_add_player.call_deferred(1)
|
_add_player.call_deferred(1)
|
||||||
|
|
||||||
|
if not "--join" in OS.get_cmdline_args():
|
||||||
|
_soundtrack.finished.connect(_play_new_track)
|
||||||
|
_play_new_track()
|
||||||
|
|
||||||
|
# TODO: sync what's played for peers, server controlled
|
||||||
|
func _play_new_track():
|
||||||
|
if _playlist_remaining.size() == 0:
|
||||||
|
_playlist_remaining = PLAYLIST.duplicate()
|
||||||
|
var selection = _playlist_remaining.pick_random()
|
||||||
|
_playlist_remaining.erase(selection)
|
||||||
|
_soundtrack.stream = load(selection)
|
||||||
|
_soundtrack.play()
|
||||||
|
|
||||||
|
|
||||||
func _exit_tree() -> void:
|
func _exit_tree() -> void:
|
||||||
if not multiplayer.is_server():
|
if not multiplayer.is_server():
|
||||||
@ -60,6 +84,11 @@ func _input(event: InputEvent) -> void:
|
|||||||
_deactivate_chat()
|
_deactivate_chat()
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
# this is fine but should this be done in response to a signal instead?
|
||||||
|
_coin_label.text = "COIN: %d" % GameState.get_item_count(&"coin")
|
||||||
|
|
||||||
|
|
||||||
func _activate_chat() -> void:
|
func _activate_chat() -> void:
|
||||||
_chat_panel.show()
|
_chat_panel.show()
|
||||||
_chat_panel_inactive.hide()
|
_chat_panel_inactive.hide()
|
||||||
@ -77,7 +106,7 @@ func _deactivate_chat() -> void:
|
|||||||
|
|
||||||
func _add_player(id: int) -> void:
|
func _add_player(id: int) -> void:
|
||||||
print("add player %d" % id)
|
print("add player %d" % id)
|
||||||
var character: CharacterBody3D = _player_scene.instantiate()
|
var character: Player = _player_scene.instantiate()
|
||||||
character.id = id
|
character.id = id
|
||||||
character.name = str(id)
|
character.name = str(id)
|
||||||
_players.add_child(character, true)
|
_players.add_child(character, true)
|
||||||
@ -109,20 +138,33 @@ func _submit_chat_message(text: String) -> void:
|
|||||||
|
|
||||||
@rpc("authority", "call_local", "reliable", 1)
|
@rpc("authority", "call_local", "reliable", 1)
|
||||||
func _add_chat_message(username: String, text: String) -> void:
|
func _add_chat_message(username: String, text: String) -> void:
|
||||||
_chat_history.add_child(_make_chat_message(username, text))
|
_chat_history.add_child(_make_chat_message(username, text, false))
|
||||||
_chat_history_inactive.add_child(_make_chat_message(username, text))
|
_chat_history_inactive.add_child(_make_chat_message(username, text, true))
|
||||||
|
|
||||||
|
|
||||||
func _on_chat_history_scroll_changed(history: ScrollContainer) -> void:
|
func _on_chat_history_scroll_changed(history: ScrollContainer) -> void:
|
||||||
# keep history scrolled to the bottom
|
# keep history scrolled to the bottom
|
||||||
history.scroll_vertical = history.get_v_scroll_bar().max_value
|
history.scroll_vertical = int(history.get_v_scroll_bar().max_value)
|
||||||
|
|
||||||
|
|
||||||
func _make_chat_message(username: String, text: String) -> RichTextLabel:
|
func _fade_inactive_chat_message(p_label: RichTextLabel) -> void:
|
||||||
|
var start := Time.get_ticks_msec()
|
||||||
|
while true:
|
||||||
|
var now := Time.get_ticks_msec()
|
||||||
|
if now - start >= 10000: break
|
||||||
|
p_label.add_theme_color_override("default_color", Color(0, 0, 0, 1.0 - (now - start) / 10000.0 ))
|
||||||
|
await get_tree().process_frame
|
||||||
|
p_label.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func _make_chat_message(username: String, text: String, inactive: bool) -> RichTextLabel:
|
||||||
var label := RichTextLabel.new()
|
var label := RichTextLabel.new()
|
||||||
label.bbcode_enabled = true
|
label.bbcode_enabled = true
|
||||||
label.fit_content = true
|
label.fit_content = true
|
||||||
label.append_text("[color=red]%s[/color] %s" % [username.replace("[", "[lb]"), text.replace("[", "[lb]")])
|
label.append_text("[color=red]%s[/color] %s" % [username.replace("[", "[lb]"), text.replace("[", "[lb]")])
|
||||||
|
if inactive:
|
||||||
|
label.add_theme_color_override("default_color", Color.BLACK)
|
||||||
|
_fade_inactive_chat_message(label)
|
||||||
return label
|
return label
|
||||||
|
|
||||||
|
|
||||||
@ -131,6 +173,6 @@ func _on_chat_message_submitted(new_text := "") -> void:
|
|||||||
_deactivate_chat()
|
_deactivate_chat()
|
||||||
return
|
return
|
||||||
|
|
||||||
_submit_chat_message.rpc_id(1, _chat_input.text)
|
_submit_chat_message.rpc_id(1, new_text)
|
||||||
_chat_input.clear()
|
_chat_input.clear()
|
||||||
_deactivate_chat()
|
_deactivate_chat()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=13 format=3 uid="uid://oyvhcwq60v2"]
|
[gd_scene load_steps=16 format=3 uid="uid://oyvhcwq60v2"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/ingame.gd" id="1_akuuj"]
|
[ext_resource type="Script" path="res://src/ingame/ingame.gd" id="1_akuuj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cs8c570bxh6u" path="res://src/ingame/player.tscn" id="2_w1gjc"]
|
[ext_resource type="PackedScene" uid="uid://cs8c570bxh6u" path="res://src/ingame/player.tscn" id="2_w1gjc"]
|
||||||
@ -32,9 +32,21 @@ sky = SubResource("Sky_ygvd3")
|
|||||||
ambient_light_color = Color(0, 0.164706, 0.278431, 1)
|
ambient_light_color = Color(0, 0.164706, 0.278431, 1)
|
||||||
ambient_light_energy = 2.0
|
ambient_light_energy = 2.0
|
||||||
|
|
||||||
[node name="Ingame" type="Node3D" node_paths=PackedStringArray("_players", "_chat_panel", "_chat_input", "_chat_history_scroll", "_chat_history", "_chat_panel_inactive", "_chat_history_inactive", "_chat_history_scroll_inactive")]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_3215c"]
|
||||||
|
size = Vector3(3, 1, 3)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vx5ut"]
|
||||||
|
transparency = 1
|
||||||
|
albedo_color = Color(1, 1, 0, 0.698039)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_gygr8"]
|
||||||
|
material = SubResource("StandardMaterial3D_vx5ut")
|
||||||
|
size = Vector3(3, 1, 3)
|
||||||
|
|
||||||
|
[node name="Ingame" type="Node3D" node_paths=PackedStringArray("_soundtrack", "_players", "_chat_panel", "_chat_input", "_chat_history_scroll", "_chat_history", "_chat_panel_inactive", "_chat_history_inactive", "_chat_history_scroll_inactive", "_coin_label")]
|
||||||
script = ExtResource("1_akuuj")
|
script = ExtResource("1_akuuj")
|
||||||
_player_scene = ExtResource("2_w1gjc")
|
_player_scene = ExtResource("2_w1gjc")
|
||||||
|
_soundtrack = NodePath("Soundtrack")
|
||||||
_players = NodePath("Players")
|
_players = NodePath("Players")
|
||||||
_chat_panel = NodePath("UI/ChatPanel")
|
_chat_panel = NodePath("UI/ChatPanel")
|
||||||
_chat_input = NodePath("UI/ChatPanel/ChatInput")
|
_chat_input = NodePath("UI/ChatPanel/ChatInput")
|
||||||
@ -43,10 +55,15 @@ _chat_history = NodePath("UI/ChatPanel/ChatHistoryScroll/ChatHistory")
|
|||||||
_chat_panel_inactive = NodePath("UI/ChatPanelInactive")
|
_chat_panel_inactive = NodePath("UI/ChatPanelInactive")
|
||||||
_chat_history_inactive = NodePath("UI/ChatPanelInactive/ChatHistoryScroll/ChatHistory")
|
_chat_history_inactive = NodePath("UI/ChatPanelInactive/ChatHistoryScroll/ChatHistory")
|
||||||
_chat_history_scroll_inactive = NodePath("UI/ChatPanelInactive/ChatHistoryScroll")
|
_chat_history_scroll_inactive = NodePath("UI/ChatPanelInactive/ChatHistoryScroll")
|
||||||
|
_coin_label = NodePath("UI/CoinLabel")
|
||||||
|
|
||||||
[node name="UI" type="CanvasLayer" parent="." node_paths=PackedStringArray("_combo_timer")]
|
[node name="Soundtrack" type="AudioStreamPlayer" parent="."]
|
||||||
|
bus = &"Music"
|
||||||
|
|
||||||
|
[node name="UI" type="CanvasLayer" parent="." node_paths=PackedStringArray("_combo_timer", "_combo_label")]
|
||||||
script = ExtResource("3_p340v")
|
script = ExtResource("3_p340v")
|
||||||
_combo_timer = NodePath("ComboTimer")
|
_combo_timer = NodePath("ComboTimer")
|
||||||
|
_combo_label = NodePath("Combo")
|
||||||
|
|
||||||
[node name="ChatPanel" type="Panel" parent="UI"]
|
[node name="ChatPanel" type="Panel" parent="UI"]
|
||||||
visible = false
|
visible = false
|
||||||
@ -138,29 +155,30 @@ vertical_scroll_mode = 3
|
|||||||
[node name="ChatHistory" type="VBoxContainer" parent="UI/ChatPanelInactive/ChatHistoryScroll"]
|
[node name="ChatHistory" type="VBoxContainer" parent="UI/ChatPanelInactive/ChatHistoryScroll"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 10
|
||||||
|
|
||||||
[node name="Combo" type="Label" parent="UI"]
|
|
||||||
visible = false
|
|
||||||
self_modulate = Color(0.534784, 0.97046, 3.46541e-06, 1)
|
|
||||||
anchors_preset = 8
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_top = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
anchor_bottom = 0.5
|
|
||||||
offset_left = -20.0
|
|
||||||
offset_top = -11.5
|
|
||||||
offset_right = 20.0
|
|
||||||
offset_bottom = 11.5
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
size_flags_horizontal = 4
|
|
||||||
text = "+5!"
|
|
||||||
|
|
||||||
[node name="ComboTimer" type="Timer" parent="UI"]
|
[node name="ComboTimer" type="Timer" parent="UI"]
|
||||||
wait_time = 3.0
|
wait_time = 3.0
|
||||||
one_shot = true
|
one_shot = true
|
||||||
|
|
||||||
|
[node name="CoinLabel" type="RichTextLabel" parent="UI"]
|
||||||
|
clip_contents = false
|
||||||
|
offset_left = 16.0
|
||||||
|
offset_top = 16.0
|
||||||
|
offset_right = 192.0
|
||||||
|
offset_bottom = 40.0
|
||||||
|
theme_override_constants/outline_size = 6
|
||||||
|
text = "Coins: 0"
|
||||||
|
|
||||||
|
[node name="Combo" type="RichTextLabel" parent="UI"]
|
||||||
|
clip_contents = false
|
||||||
|
offset_left = 16.0
|
||||||
|
offset_top = 32.0
|
||||||
|
offset_right = 192.0
|
||||||
|
offset_bottom = 56.0
|
||||||
|
theme_override_colors/default_color = Color(0.695503, 0.695503, 0.695503, 1)
|
||||||
|
theme_override_constants/outline_size = 6
|
||||||
|
|
||||||
[node name="CSGBox3D" type="CSGBox3D" parent="."]
|
[node name="CSGBox3D" type="CSGBox3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 7.45058e-09, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 7.45058e-09, 0)
|
||||||
collision_mask = 0
|
collision_mask = 0
|
||||||
@ -217,9 +235,6 @@ environment = SubResource("Environment_ijk14")
|
|||||||
transform = Transform3D(0.943957, 0.3178, 0.0891561, 0, -0.270113, 0.962829, 0.33007, -0.908868, -0.254975, 0, 0, 0)
|
transform = Transform3D(0.943957, 0.3178, 0.0891561, 0, -0.270113, 0.962829, 0.33007, -0.908868, -0.254975, 0, 0, 0)
|
||||||
light_energy = 2.0
|
light_energy = 2.0
|
||||||
|
|
||||||
[node name="SpawnPoint" type="Marker3D" parent="." groups=["spawn_points"]]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
|
||||||
|
|
||||||
[node name="PlayerSpawner" type="MultiplayerSpawner" parent="."]
|
[node name="PlayerSpawner" type="MultiplayerSpawner" parent="."]
|
||||||
_spawnable_scenes = PackedStringArray("res://src/ingame/player.tscn")
|
_spawnable_scenes = PackedStringArray("res://src/ingame/player.tscn")
|
||||||
spawn_path = NodePath("../Players")
|
spawn_path = NodePath("../Players")
|
||||||
@ -288,6 +303,28 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.59598, 1.39617, -1.62022)
|
|||||||
[node name="Pipe" parent="." instance=ExtResource("4_mltw3")]
|
[node name="Pipe" parent="." instance=ExtResource("4_mltw3")]
|
||||||
transform = Transform3D(0.999929, -0.0119378, 0, -0.0119378, -0.999929, 8.74228e-08, -1.04363e-09, -8.74165e-08, -1, -7, 6.79123, 7)
|
transform = Transform3D(0.999929, -0.0119378, 0, -0.0119378, -0.999929, 8.74228e-08, -1.04363e-09, -8.74165e-08, -1, -7, 6.79123, 7)
|
||||||
|
|
||||||
|
[node name="SpawnPoints" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="SpawnPoint" type="Marker3D" parent="SpawnPoints" groups=["spawn_points"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||||
|
|
||||||
|
[node name="SpawnPoint2" type="Marker3D" parent="SpawnPoints" groups=["spawn_points"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.15702, 1.04855, 5.88574)
|
||||||
|
|
||||||
|
[node name="SpawnPoint3" type="Marker3D" parent="SpawnPoints" groups=["spawn_points"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.43229, 0.627689, 7.20138)
|
||||||
|
|
||||||
|
[node name="SellBox" type="StaticBody3D" parent="." groups=["sell_boxes"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 0, 0)
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 4
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="SellBox"]
|
||||||
|
shape = SubResource("BoxShape3D_3215c")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="SellBox"]
|
||||||
|
mesh = SubResource("BoxMesh_gygr8")
|
||||||
|
|
||||||
[connection signal="text_submitted" from="UI/ChatPanel/ChatInput" to="." method="_on_chat_message_submitted"]
|
[connection signal="text_submitted" from="UI/ChatPanel/ChatInput" to="." method="_on_chat_message_submitted"]
|
||||||
[connection signal="pressed" from="UI/ChatPanel/ChatSendButton" to="." method="_on_chat_message_submitted"]
|
[connection signal="pressed" from="UI/ChatPanel/ChatSendButton" to="." method="_on_chat_message_submitted"]
|
||||||
[connection signal="timeout" from="UI/ComboTimer" to="UI" method="_on_combo_timer_timeout"]
|
[connection signal="timeout" from="UI/ComboTimer" to="UI" method="_on_combo_timer_timeout"]
|
||||||
|
162
src/ingame/item_bomb.tscn
Normal file
162
src/ingame/item_bomb.tscn
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
[gd_scene load_steps=17 format=3 uid="uid://bpvbnlhpth4w7"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/bomb.gd" id="1_27lur"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dxb5f3il2h1ur" path="res://src/ingame/quad_viewmodel.tscn" id="2_fy6j6"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dy3ngeohp1uqf" path="res://assets/sfx/land.wav" id="3_1vo65"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dkxv7wbq8s1gs" path="res://assets/sfx/coinsplash.ogg" id="4_fyu6c"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dgo2frvws2o6f" path="res://assets/coin.png" id="5_om8wy"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_0ebrr"]
|
||||||
|
properties/0/path = NodePath(".:position")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:is_dead")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 2
|
||||||
|
properties/2/path = NodePath(".:rotation")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 1
|
||||||
|
properties/3/path = NodePath(".:item_bundle")
|
||||||
|
properties/3/spawn = true
|
||||||
|
properties/3/replication_mode = 2
|
||||||
|
properties/4/path = NodePath("Model:visible")
|
||||||
|
properties/4/spawn = true
|
||||||
|
properties/4/replication_mode = 2
|
||||||
|
properties/5/path = NodePath("SellParticles:emitting")
|
||||||
|
properties/5/spawn = true
|
||||||
|
properties/5/replication_mode = 2
|
||||||
|
properties/6/path = NodePath("DropSound:playing")
|
||||||
|
properties/6/spawn = true
|
||||||
|
properties/6/replication_mode = 2
|
||||||
|
properties/7/path = NodePath("SellSound:playing")
|
||||||
|
properties/7/spawn = true
|
||||||
|
properties/7/replication_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_v7dnr"]
|
||||||
|
albedo_color = Color(0, 1, 1, 1)
|
||||||
|
roughness = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_rjbgm"]
|
||||||
|
direction = Vector3(0, 1, 0)
|
||||||
|
initial_velocity_min = 5.0
|
||||||
|
initial_velocity_max = 5.0
|
||||||
|
gravity = Vector3(0, -8, 0)
|
||||||
|
collision_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_bhdh4"]
|
||||||
|
radius = 0.1
|
||||||
|
height = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_6c830"]
|
||||||
|
radius = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_y6453"]
|
||||||
|
radius = 1.5
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_qoklw"]
|
||||||
|
offsets = PackedFloat32Array(0.0454545, 0.836364, 0.981818)
|
||||||
|
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture1D" id="GradientTexture1D_fdtmr"]
|
||||||
|
gradient = SubResource("Gradient_qoklw")
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_yncjw"]
|
||||||
|
lifetime_randomness = 0.2
|
||||||
|
inherit_velocity_ratio = 0.1
|
||||||
|
direction = Vector3(0, 1, 0)
|
||||||
|
spread = 180.0
|
||||||
|
initial_velocity_max = 3.0
|
||||||
|
gravity = Vector3(0, 0, 0)
|
||||||
|
linear_accel_min = -6.9
|
||||||
|
linear_accel_max = -3.45
|
||||||
|
color_ramp = SubResource("GradientTexture1D_fdtmr")
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ooyci"]
|
||||||
|
transparency = 1
|
||||||
|
shading_mode = 0
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_texture = ExtResource("5_om8wy")
|
||||||
|
|
||||||
|
[sub_resource type="QuadMesh" id="QuadMesh_4d5bh"]
|
||||||
|
material = SubResource("StandardMaterial3D_ooyci")
|
||||||
|
size = Vector2(0.25, 0.25)
|
||||||
|
|
||||||
|
[node name="ItemBomb" type="Node3D" node_paths=PackedStringArray("_splash_small_sound", "_sell_sound", "_model", "_sell_particles", "_picking_area", "body")]
|
||||||
|
script = ExtResource("1_27lur")
|
||||||
|
_splash_small_sound = NodePath("DropSound")
|
||||||
|
_sell_sound = NodePath("SellSound")
|
||||||
|
_model = NodePath("Model")
|
||||||
|
_sell_particles = NodePath("SellParticles")
|
||||||
|
_picking_area = NodePath("PickingArea")
|
||||||
|
body = NodePath("RigidBody3D")
|
||||||
|
billboard = true
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_0ebrr")
|
||||||
|
|
||||||
|
[node name="Model" parent="." instance=ExtResource("2_fy6j6")]
|
||||||
|
|
||||||
|
[node name="SplashParticles" type="GPUParticles3D" parent="."]
|
||||||
|
visible = false
|
||||||
|
material_override = SubResource("StandardMaterial3D_v7dnr")
|
||||||
|
emitting = false
|
||||||
|
amount = 32
|
||||||
|
lifetime = 2.0
|
||||||
|
one_shot = true
|
||||||
|
explosiveness = 1.0
|
||||||
|
randomness = 1.0
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_rjbgm")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_bhdh4")
|
||||||
|
|
||||||
|
[node name="RigidBody3D" type="RigidBody3D" parent="."]
|
||||||
|
top_level = true
|
||||||
|
collision_layer = 4
|
||||||
|
collision_mask = 3
|
||||||
|
contact_monitor = true
|
||||||
|
max_contacts_reported = 1
|
||||||
|
linear_damp_mode = 1
|
||||||
|
linear_damp = 0.3
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D"]
|
||||||
|
shape = SubResource("SphereShape3D_6c830")
|
||||||
|
|
||||||
|
[node name="SplashArea" type="Area3D" parent="RigidBody3D"]
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 8
|
||||||
|
monitorable = false
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D/SplashArea"]
|
||||||
|
shape = SubResource("SphereShape3D_y6453")
|
||||||
|
|
||||||
|
[node name="PickingArea" type="Area3D" parent="."]
|
||||||
|
collision_layer = 16
|
||||||
|
collision_mask = 0
|
||||||
|
monitoring = false
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="PickingArea"]
|
||||||
|
shape = SubResource("SphereShape3D_6c830")
|
||||||
|
|
||||||
|
[node name="DropSound" type="AudioStreamPlayer3D" parent="."]
|
||||||
|
stream = ExtResource("3_1vo65")
|
||||||
|
volume_db = 10.0
|
||||||
|
bus = &"SoundEffects"
|
||||||
|
|
||||||
|
[node name="SellSound" type="AudioStreamPlayer3D" parent="."]
|
||||||
|
stream = ExtResource("4_fyu6c")
|
||||||
|
volume_db = 2.0
|
||||||
|
bus = &"SoundEffects"
|
||||||
|
|
||||||
|
[node name="SellParticles" type="GPUParticles3D" parent="."]
|
||||||
|
emitting = false
|
||||||
|
amount = 32
|
||||||
|
lifetime = 2.0
|
||||||
|
one_shot = true
|
||||||
|
speed_scale = 0.5
|
||||||
|
explosiveness = 1.0
|
||||||
|
randomness = 0.4
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_yncjw")
|
||||||
|
draw_pass_1 = SubResource("QuadMesh_4d5bh")
|
||||||
|
|
||||||
|
[connection signal="body_entered" from="RigidBody3D" to="." method="_on_body_entered"]
|
||||||
|
[connection signal="area_entered" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_entered"]
|
||||||
|
[connection signal="area_exited" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_exited"]
|
@ -2,6 +2,7 @@ extends Node3D
|
|||||||
|
|
||||||
@export var _projectile_scene: PackedScene
|
@export var _projectile_scene: PackedScene
|
||||||
@export var _projectile_holder: Node
|
@export var _projectile_holder: Node
|
||||||
|
@warning_ignore("unused_private_class_variable")
|
||||||
@export var _production_timer: Timer
|
@export var _production_timer: Timer
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ func _drop_water() -> void:
|
|||||||
_projectile_holder.add_child(new_projectile, true)
|
_projectile_holder.add_child(new_projectile, true)
|
||||||
new_projectile.set_multiplayer_authority(1)
|
new_projectile.set_multiplayer_authority(1)
|
||||||
new_projectile.body.process_mode = Node.PROCESS_MODE_INHERIT
|
new_projectile.body.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
new_projectile.set_global_pos(global_position)
|
new_projectile.set_global_pos.rpc(global_position)
|
||||||
|
|
||||||
|
|
||||||
func _on_drop_timer_timeout() -> void:
|
func _on_drop_timer_timeout() -> void:
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
[ext_resource type="Script" path="res://src/ingame/pipe.gd" id="1_ckmpn"]
|
[ext_resource type="Script" path="res://src/ingame/pipe.gd" id="1_ckmpn"]
|
||||||
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="2_3sfu2"]
|
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="2_3sfu2"]
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_bgwg2"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ecwtt"]
|
||||||
cull_mode = 2
|
albedo_color = Color(0, 1, 1, 1)
|
||||||
albedo_color = Color(0.0313726, 1, 1, 1)
|
|
||||||
|
|
||||||
[sub_resource type="PlaneMesh" id="PlaneMesh_g3bb5"]
|
[sub_resource type="SphereMesh" id="SphereMesh_504u5"]
|
||||||
lightmap_size_hint = Vector2i(12, 12)
|
material = SubResource("StandardMaterial3D_ecwtt")
|
||||||
material = SubResource("StandardMaterial3D_bgwg2")
|
height = 0.001
|
||||||
|
rings = 1
|
||||||
|
|
||||||
[node name="Pipe" type="Node3D" node_paths=PackedStringArray("_projectile_holder", "_production_timer")]
|
[node name="Pipe" type="Node3D" node_paths=PackedStringArray("_projectile_holder", "_production_timer")]
|
||||||
script = ExtResource("1_ckmpn")
|
script = ExtResource("1_ckmpn")
|
||||||
@ -22,12 +22,12 @@ _spawnable_scenes = PackedStringArray("res://src/ingame/water_bomb.tscn")
|
|||||||
spawn_path = NodePath("../ProjectileHolder")
|
spawn_path = NodePath("../ProjectileHolder")
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
mesh = SubResource("PlaneMesh_g3bb5")
|
mesh = SubResource("SphereMesh_504u5")
|
||||||
|
|
||||||
[node name="ProjectileHolder" type="Node" parent="."]
|
[node name="ProjectileHolder" type="Node" parent="."]
|
||||||
|
|
||||||
[node name="DropTimer" type="Timer" parent="."]
|
[node name="DropTimer" type="Timer" parent="."]
|
||||||
wait_time = 2.0
|
wait_time = 2.5
|
||||||
autostart = true
|
autostart = true
|
||||||
|
|
||||||
[connection signal="timeout" from="DropTimer" to="." method="_on_drop_timer_timeout"]
|
[connection signal="timeout" from="DropTimer" to="." method="_on_drop_timer_timeout"]
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
extends CharacterBody3D
|
class_name Player extends CharacterBody3D
|
||||||
|
|
||||||
|
|
||||||
const SPEED = 5.0
|
const SPEED = 5.0
|
||||||
const JUMP_VELOCITY = 4.5
|
const JUMP_VELOCITY = 4.5
|
||||||
|
|
||||||
@export var _projectile_scene: PackedScene
|
|
||||||
|
|
||||||
@export var _projectile_holder: Node
|
@export var _projectile_holder: Node
|
||||||
@export var _projectile_point: Marker3D
|
@export var _projectile_point: Marker3D
|
||||||
@export var _camera_pivot: Node3D
|
@export var _camera_pivot: Node3D
|
||||||
@ -17,7 +14,7 @@ const JUMP_VELOCITY = 4.5
|
|||||||
@export var input_dir := Vector2()
|
@export var input_dir := Vector2()
|
||||||
@export var input_jumped := false
|
@export var input_jumped := false
|
||||||
|
|
||||||
var _max_speed := 12
|
var _max_speed := 16
|
||||||
var _mouse_sensitivity := 0.008 # radians/pixel
|
var _mouse_sensitivity := 0.008 # radians/pixel
|
||||||
|
|
||||||
var _projectile_speed := 12.0
|
var _projectile_speed := 12.0
|
||||||
@ -25,7 +22,14 @@ var _projectile_speed := 12.0
|
|||||||
var _interaction_selection: Node3D
|
var _interaction_selection: Node3D
|
||||||
|
|
||||||
var controls_disabled := false
|
var controls_disabled := false
|
||||||
var held_thing: String
|
@export var held_thing := { "item_id": &"empty_hand", "count": 0 }
|
||||||
|
|
||||||
|
## Whether picking input is pressed right now
|
||||||
|
var _picking := false
|
||||||
|
## Used to limit picking rate, potentially upgradable
|
||||||
|
var _last_picked := 0
|
||||||
|
var _picks_per_second := 3
|
||||||
|
|
||||||
|
|
||||||
# What the others see.
|
# What the others see.
|
||||||
func _init_bystander() -> void:
|
func _init_bystander() -> void:
|
||||||
@ -41,6 +45,7 @@ func _ready() -> void:
|
|||||||
$Model.hide()
|
$Model.hide()
|
||||||
_camera.make_current()
|
_camera.make_current()
|
||||||
|
|
||||||
|
# TODO: reliable rng
|
||||||
var spawn_point: Marker3D = get_tree().get_nodes_in_group("spawn_points").pick_random()
|
var spawn_point: Marker3D = get_tree().get_nodes_in_group("spawn_points").pick_random()
|
||||||
global_position = spawn_point.global_position
|
global_position = spawn_point.global_position
|
||||||
reset_physics_interpolation()
|
reset_physics_interpolation()
|
||||||
@ -58,12 +63,16 @@ func _physics_process(delta: float) -> void:
|
|||||||
if id == multiplayer.get_unique_id():
|
if id == multiplayer.get_unique_id():
|
||||||
var collider: Object = null
|
var collider: Object = null
|
||||||
if _line_of_sight.is_colliding():
|
if _line_of_sight.is_colliding():
|
||||||
collider = _line_of_sight.get_collider(0)
|
var possible_collider = _line_of_sight.get_collider(0)
|
||||||
|
if empty_handed(): collider = possible_collider
|
||||||
|
elif possible_collider and \
|
||||||
|
GameState.are_bundles_stackable(held_thing, possible_collider.owner.item_bundle):
|
||||||
|
collider = possible_collider
|
||||||
if collider != _interaction_selection:
|
if collider != _interaction_selection:
|
||||||
if _interaction_selection != null:
|
if _interaction_selection != null:
|
||||||
_interaction_selection.get_parent().mark_non_interactive()
|
_interaction_selection.get_parent().mark_non_interactive()
|
||||||
if collider != null:
|
if collider != null:
|
||||||
collider.get_parent().mark_interactive()
|
collider.owner.mark_interactive()
|
||||||
_interaction_selection = collider
|
_interaction_selection = collider
|
||||||
|
|
||||||
# Add the gravity.
|
# Add the gravity.
|
||||||
@ -75,7 +84,6 @@ func _physics_process(delta: float) -> void:
|
|||||||
velocity.y = JUMP_VELOCITY
|
velocity.y = JUMP_VELOCITY
|
||||||
|
|
||||||
# Get the input direction and handle the movement/deceleration.
|
# Get the input direction and handle the movement/deceleration.
|
||||||
# As good practice, you should replace UI actions with custom gameplay actions.
|
|
||||||
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
||||||
if direction:
|
if direction:
|
||||||
velocity.x = direction.x * SPEED
|
velocity.x = direction.x * SPEED
|
||||||
@ -84,19 +92,61 @@ func _physics_process(delta: float) -> void:
|
|||||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||||
velocity.z = move_toward(velocity.z, 0, SPEED)
|
velocity.z = move_toward(velocity.z, 0, SPEED)
|
||||||
|
|
||||||
move_and_slide()
|
if velocity.length() > _max_speed:
|
||||||
|
velocity = velocity.clampf(0, _max_speed)
|
||||||
|
|
||||||
|
$StairStepper.stair_step_up(direction)
|
||||||
|
|
||||||
|
if move_and_slide() and is_on_floor():
|
||||||
|
for idx in range(get_slide_collision_count()):
|
||||||
|
var collision := get_slide_collision(idx)
|
||||||
|
if collision.get_collider().is_in_group("voids"):
|
||||||
|
# TODO: reliable rng
|
||||||
|
var spawn_point: Marker3D = get_tree().get_nodes_in_group("spawn_points").pick_random()
|
||||||
|
global_position = spawn_point.global_position
|
||||||
|
reset_physics_interpolation()
|
||||||
|
|
||||||
|
$StairStepper.stair_step_down()
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
func hold_thing() -> void:
|
func hold_thing(p_bundle: Dictionary) -> void:
|
||||||
held_thing = "water"
|
var item := GameState.fetch().INVENTORY_ITEM_DB[p_bundle["item_id"]] as InventoryItem
|
||||||
_camera_pivot.get_node("HeldViewmodel").show()
|
held_thing = p_bundle
|
||||||
|
var base_node := _camera_pivot.get_node("HeldViewmodel")
|
||||||
|
for child in base_node.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
if item.model != null:
|
||||||
|
var model = item.model.instantiate()
|
||||||
|
base_node.add_child(model)
|
||||||
|
else:
|
||||||
|
# Create a icon sprite based one instead.
|
||||||
|
var model := preload("res://src/ingame/quad_viewmodel.tscn").instantiate()
|
||||||
|
model.reflect_bundle(p_bundle)
|
||||||
|
base_node.add_child(model)
|
||||||
|
|
||||||
|
if item.model != null and id == multiplayer.get_unique_id():
|
||||||
|
# Disable depth test and increase render priority.
|
||||||
|
# TODO: in more complex scenarios model scene might want to have its own callback for this.
|
||||||
|
for model in base_node.get_children():
|
||||||
|
for submodel in model.get_children():
|
||||||
|
var mesh := submodel.mesh.duplicate() as Mesh
|
||||||
|
var material := mesh.surface_get_material(0).duplicate()
|
||||||
|
material.render_priority += 1
|
||||||
|
material.no_depth_test = true
|
||||||
|
mesh.surface_set_material(0, material)
|
||||||
|
submodel.mesh = mesh
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
func throw_thing() -> void:
|
func throw_thing() -> void:
|
||||||
held_thing = ""
|
held_thing = { "item_id": &"empty_hand", "count": 0 }
|
||||||
_camera_pivot.get_node("HeldViewmodel").hide()
|
for child in _camera_pivot.get_node("HeldViewmodel").get_children():
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func empty_handed() -> bool:
|
||||||
|
return held_thing["item_id"] == &"empty_hand"
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
@ -109,16 +159,19 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
_camera_pivot.rotation.x = clamp(_camera_pivot.rotation.x, -1.2, 1.2)
|
_camera_pivot.rotation.x = clamp(_camera_pivot.rotation.x, -1.2, 1.2)
|
||||||
return
|
return
|
||||||
|
|
||||||
if event.is_action_pressed("pick") and held_thing == "":
|
if event.is_action_pressed("pick"):
|
||||||
if _interaction_selection != null:
|
_picking = true
|
||||||
_interaction_selection.get_parent().get_picked_up.rpc()
|
if event.is_action_released("pick"):
|
||||||
hold_thing.rpc()
|
_picking = false
|
||||||
|
|
||||||
if event.is_action_pressed("fire") and held_thing != "":
|
if event.is_action_pressed("fire") and not empty_handed():
|
||||||
var new_projectile: Node3D = _projectile_scene.instantiate()
|
var item := GameState.fetch().INVENTORY_ITEM_DB[held_thing["item_id"]] as InventoryItem
|
||||||
|
var new_projectile: Node3D = item.bomb.instantiate()
|
||||||
_projectile_holder.add_child(new_projectile, true)
|
_projectile_holder.add_child(new_projectile, true)
|
||||||
_set_projectile_authority.rpc(new_projectile.get_path(), id)
|
_set_projectile_authority.rpc(new_projectile.get_path(), id)
|
||||||
|
new_projectile.set_item_bundle.rpc(held_thing)
|
||||||
new_projectile.set_global_pos.rpc(_projectile_point.global_position)
|
new_projectile.set_global_pos.rpc(_projectile_point.global_position)
|
||||||
|
new_projectile.rotation = rotation
|
||||||
new_projectile.sender_body = self
|
new_projectile.sender_body = self
|
||||||
new_projectile.sender_id = id
|
new_projectile.sender_id = id
|
||||||
|
|
||||||
@ -138,10 +191,23 @@ func _set_projectile_authority(path: NodePath, authority_id: int) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _process_input() -> void:
|
func _process_input() -> void:
|
||||||
if controls_disabled:
|
if controls_disabled or id != multiplayer.get_unique_id():
|
||||||
input_dir = Vector2.ZERO
|
input_dir = Vector2.ZERO
|
||||||
input_jumped = false
|
input_jumped = false
|
||||||
return
|
return
|
||||||
|
|
||||||
input_dir = Input.get_vector("strafe_left", "strafe_right", "move_forward", "move_backward")
|
input_dir = Input.get_vector("strafe_left", "strafe_right", "move_forward", "move_backward")
|
||||||
input_jumped = Input.is_action_just_pressed("jump")
|
input_jumped = Input.is_action_just_pressed("jump")
|
||||||
|
|
||||||
|
if _picking and (Time.get_ticks_msec() - _last_picked) >= (1000.0 / _picks_per_second) \
|
||||||
|
and _interaction_selection != null:
|
||||||
|
if empty_handed():
|
||||||
|
_last_picked = Time.get_ticks_msec()
|
||||||
|
_interaction_selection.owner.get_picked_up.rpc()
|
||||||
|
hold_thing.rpc(_interaction_selection.owner.item_bundle)
|
||||||
|
elif GameState.are_bundles_stackable(held_thing, _interaction_selection.owner.item_bundle):
|
||||||
|
_last_picked = Time.get_ticks_msec()
|
||||||
|
_interaction_selection.owner.get_picked_up.rpc()
|
||||||
|
var bundle := GameState.combine_bundles(held_thing, _interaction_selection.owner.item_bundle)
|
||||||
|
hold_thing.rpc(bundle)
|
||||||
|
#_line_of_sight.force_shapecast_update()
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
[gd_scene load_steps=12 format=3 uid="uid://cs8c570bxh6u"]
|
[gd_scene load_steps=8 format=3 uid="uid://cs8c570bxh6u"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/player.gd" id="1_isrmf"]
|
[ext_resource type="Script" path="res://src/ingame/player.gd" id="1_r8lgj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="2_naek4"]
|
[ext_resource type="Script" path="res://src/lib/player_character.gd" id="1_sba4x"]
|
||||||
[ext_resource type="AudioStream" uid="uid://3dlhs18w1fa2" path="res://assets/sfx/boom.wav" id="3_u2hxa"]
|
[ext_resource type="AudioStream" uid="uid://3dlhs18w1fa2" path="res://assets/sfx/boom.wav" id="3_u2hxa"]
|
||||||
[ext_resource type="Shader" path="res://scenes/interactivity_outline.gdshader" id="4_a2qfj"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://s2a1pry5fw8f" path="res://scenes/water_bomb_model.tscn" id="4_bfvih"]
|
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_2xotl"]
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_2xotl"]
|
||||||
properties/0/path = NodePath(".:position")
|
properties/0/path = NodePath(".:position")
|
||||||
@ -25,6 +23,9 @@ properties/4/replication_mode = 2
|
|||||||
properties/5/path = NodePath("ShotSound:playing")
|
properties/5/path = NodePath("ShotSound:playing")
|
||||||
properties/5/spawn = true
|
properties/5/spawn = true
|
||||||
properties/5/replication_mode = 2
|
properties/5/replication_mode = 2
|
||||||
|
properties/6/path = NodePath(".:held_thing")
|
||||||
|
properties/6/spawn = true
|
||||||
|
properties/6/replication_mode = 2
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_hi8jw"]
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_hi8jw"]
|
||||||
|
|
||||||
@ -32,24 +33,9 @@ properties/5/replication_mode = 2
|
|||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_rsfjy"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_rsfjy"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_nch7m"]
|
|
||||||
resource_local_to_scene = true
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("4_a2qfj")
|
|
||||||
shader_parameter/color = Color(1, 1, 1, 0)
|
|
||||||
shader_parameter/size = 1.24
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_x7r08"]
|
|
||||||
resource_local_to_scene = true
|
|
||||||
next_pass = SubResource("ShaderMaterial_nch7m")
|
|
||||||
albedo_color = Color(0.0936238, 0.825356, 1, 1)
|
|
||||||
metallic = 0.8
|
|
||||||
roughness = 0.4
|
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("_projectile_holder", "_projectile_point", "_camera_pivot", "_camera", "_line_of_sight", "_shot_sound")]
|
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("_projectile_holder", "_projectile_point", "_camera_pivot", "_camera", "_line_of_sight", "_shot_sound")]
|
||||||
collision_layer = 2
|
collision_layer = 2
|
||||||
script = ExtResource("1_isrmf")
|
script = ExtResource("1_r8lgj")
|
||||||
_projectile_scene = ExtResource("2_naek4")
|
|
||||||
_projectile_holder = NodePath("ProjectileHolder")
|
_projectile_holder = NodePath("ProjectileHolder")
|
||||||
_projectile_point = NodePath("ProjectilePoint")
|
_projectile_point = NodePath("ProjectilePoint")
|
||||||
_camera_pivot = NodePath("CameraPivot")
|
_camera_pivot = NodePath("CameraPivot")
|
||||||
@ -57,11 +43,14 @@ _camera = NodePath("CameraPivot/Camera3D")
|
|||||||
_line_of_sight = NodePath("CameraPivot/LineOfSight")
|
_line_of_sight = NodePath("CameraPivot/LineOfSight")
|
||||||
_shot_sound = NodePath("ShotSound")
|
_shot_sound = NodePath("ShotSound")
|
||||||
|
|
||||||
|
[node name="StairStepper" type="Node" parent="."]
|
||||||
|
script = ExtResource("1_sba4x")
|
||||||
|
|
||||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
replication_config = SubResource("SceneReplicationConfig_2xotl")
|
replication_config = SubResource("SceneReplicationConfig_2xotl")
|
||||||
|
|
||||||
[node name="ProjectileSpawner" type="MultiplayerSpawner" parent="."]
|
[node name="ProjectileSpawner" type="MultiplayerSpawner" parent="."]
|
||||||
_spawnable_scenes = PackedStringArray("res://src/ingame/water_bomb.tscn")
|
_spawnable_scenes = PackedStringArray("res://src/ingame/water_bomb.tscn", "res://src/ingame/item_bomb.tscn")
|
||||||
spawn_path = NodePath("../ProjectileHolder")
|
spawn_path = NodePath("../ProjectileHolder")
|
||||||
|
|
||||||
[node name="ProjectileHolder" type="Node" parent="."]
|
[node name="ProjectileHolder" type="Node" parent="."]
|
||||||
@ -95,10 +84,6 @@ debug_shape_custom_color = Color(0.628721, 0, 0.256939, 1)
|
|||||||
|
|
||||||
[node name="HeldViewmodel" type="Node3D" parent="CameraPivot"]
|
[node name="HeldViewmodel" type="Node3D" parent="CameraPivot"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, -1)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, -1)
|
||||||
visible = false
|
|
||||||
|
|
||||||
[node name="Model" parent="CameraPivot/HeldViewmodel" instance=ExtResource("4_bfvih")]
|
|
||||||
material_override = SubResource("StandardMaterial3D_x7r08")
|
|
||||||
|
|
||||||
[node name="ShotSound" type="AudioStreamPlayer3D" parent="."]
|
[node name="ShotSound" type="AudioStreamPlayer3D" parent="."]
|
||||||
stream = ExtResource("3_u2hxa")
|
stream = ExtResource("3_u2hxa")
|
||||||
|
13
src/ingame/quad_viewmodel.gd
Normal file
13
src/ingame/quad_viewmodel.gd
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var mesh: MeshInstance3D
|
||||||
|
@export var count_label: Label3D
|
||||||
|
|
||||||
|
|
||||||
|
func reflect_bundle(p_bundle: Dictionary) -> void:
|
||||||
|
var item = GameState.fetch().INVENTORY_ITEM_DB[p_bundle["item_id"]]
|
||||||
|
mesh.material_override.set("shader_parameter/albedo_texture", item.icon)
|
||||||
|
if item.stackable:
|
||||||
|
count_label.text = str(p_bundle["count"]) + "\n=\n" + str(item.stack_limit)
|
||||||
|
else:
|
||||||
|
count_label.text = str(p_bundle["count"])
|
40
src/ingame/quad_viewmodel.tscn
Normal file
40
src/ingame/quad_viewmodel.tscn
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://dxb5f3il2h1ur"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/quad_viewmodel.gd" id="1_l2s4x"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dgo2frvws2o6f" path="res://assets/coin.png" id="2_k1r4m"]
|
||||||
|
[ext_resource type="Shader" path="res://assets/shaders/interactivity_outline2.gdshader" id="2_xpghy"]
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_5wlqs"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("2_xpghy")
|
||||||
|
shader_parameter/width = 1.0
|
||||||
|
shader_parameter/outline_color = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/albedo_texture = ExtResource("2_k1r4m")
|
||||||
|
|
||||||
|
[sub_resource type="QuadMesh" id="QuadMesh_dxt6h"]
|
||||||
|
size = Vector2(0.5, 0.5)
|
||||||
|
|
||||||
|
[node name="QuadViewmodel" type="Node3D" node_paths=PackedStringArray("mesh", "count_label")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.309578, 0)
|
||||||
|
script = ExtResource("1_l2s4x")
|
||||||
|
mesh = NodePath("Mesh")
|
||||||
|
count_label = NodePath("CountLabel")
|
||||||
|
|
||||||
|
[node name="CountLabel" type="Label3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.0502154, 0)
|
||||||
|
billboard = 1
|
||||||
|
texture_filter = 0
|
||||||
|
render_priority = 2
|
||||||
|
outline_render_priority = 1
|
||||||
|
text = "3
|
||||||
|
=
|
||||||
|
9"
|
||||||
|
font_size = 30
|
||||||
|
outline_size = 10
|
||||||
|
line_spacing = -22.0
|
||||||
|
|
||||||
|
[node name="Mesh" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.0495689, 0)
|
||||||
|
material_override = SubResource("ShaderMaterial_5wlqs")
|
||||||
|
mesh = SubResource("QuadMesh_dxt6h")
|
@ -2,7 +2,10 @@ extends Node3D
|
|||||||
|
|
||||||
@export var _need_water_drop: Sprite3D
|
@export var _need_water_drop: Sprite3D
|
||||||
@export var _production_timer: Timer
|
@export var _production_timer: Timer
|
||||||
@export var _sprite: Sprite3D
|
@export var _mesh: MeshInstance3D
|
||||||
|
@export var _area: Area3D
|
||||||
|
|
||||||
|
var item_bundle := { "item_id": &"coin_flower", "count": 1 }
|
||||||
|
|
||||||
var needs_water := true
|
var needs_water := true
|
||||||
var stage: int = 1
|
var stage: int = 1
|
||||||
@ -19,19 +22,16 @@ func _on_production_timer_timeout() -> void:
|
|||||||
_need_water_drop.show()
|
_need_water_drop.show()
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
|
||||||
func _reflect_texture(p_stage: int) -> void:
|
|
||||||
_sprite.texture = load("res://assets/sprout%s.png" % p_stage)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
func _water_shared(sender_id: int) -> void:
|
func _water_shared(sender_id: int) -> void:
|
||||||
if stage >= final_stage:
|
if stage >= final_stage:
|
||||||
return
|
return
|
||||||
stage += 1
|
stage += 1
|
||||||
_sprite.texture = load("res://assets/sprout%s.png" % stage)
|
_mesh.material_override.set("shader_parameter/albedo_texture", load("res://assets/sprout%s.png" % stage))
|
||||||
if sender_id != 0:
|
if sender_id != 0:
|
||||||
GameState.fetch().player_data[sender_id].chain_water_combo(1)
|
GameState.fetch().player_data[sender_id].chain_water_combo(1)
|
||||||
|
if stage == final_stage:
|
||||||
|
_area.collision_layer |= 1 << 4
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
@ -43,3 +43,21 @@ func water(sender_id: int) -> void:
|
|||||||
if stage != final_stage:
|
if stage != final_stage:
|
||||||
needs_water = false
|
needs_water = false
|
||||||
_production_timer.start()
|
_production_timer.start()
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func get_picked_up() -> void:
|
||||||
|
assert(stage == final_stage)
|
||||||
|
stage = 1
|
||||||
|
_mesh.material_override.set("shader_parameter/albedo_texture", load("res://assets/sprout%s.png" % stage))
|
||||||
|
_area.collision_layer ^= 1 << 4
|
||||||
|
needs_water = true
|
||||||
|
_need_water_drop.show()
|
||||||
|
|
||||||
|
|
||||||
|
func mark_interactive() -> void:
|
||||||
|
_mesh.material_override.set("shader_parameter/outline_color", Color.WHITE)
|
||||||
|
|
||||||
|
|
||||||
|
func mark_non_interactive() -> void:
|
||||||
|
_mesh.material_override.set("shader_parameter/outline_color", Color.BLACK)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
[gd_scene load_steps=6 format=3 uid="uid://bysgtksvovyur"]
|
[gd_scene load_steps=9 format=3 uid="uid://bysgtksvovyur"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/sprout.gd" id="1_snma1"]
|
[ext_resource type="Script" path="res://src/ingame/sprout.gd" id="1_snma1"]
|
||||||
[ext_resource type="Texture2D" uid="uid://d35y5ckne72qe" path="res://assets/sprout1.png" id="2_ipgad"]
|
[ext_resource type="Texture2D" uid="uid://d35y5ckne72qe" path="res://assets/sprout1.png" id="2_ipgad"]
|
||||||
|
[ext_resource type="Shader" path="res://assets/shaders/interactivity_outline2.gdshader" id="2_oa2it"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cwbl0r1e26eja" path="res://assets/drop.png" id="3_kghdv"]
|
[ext_resource type="Texture2D" uid="uid://cwbl0r1e26eja" path="res://assets/drop.png" id="3_kghdv"]
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_rs2qp"]
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_rs2qp"]
|
||||||
@ -12,27 +13,36 @@ properties/1/path = NodePath("NeedWaterDrop:visible")
|
|||||||
properties/1/spawn = true
|
properties/1/spawn = true
|
||||||
properties/1/replication_mode = 2
|
properties/1/replication_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_3ul7y"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("2_oa2it")
|
||||||
|
shader_parameter/width = 1.0
|
||||||
|
shader_parameter/outline_color = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/albedo_texture = ExtResource("2_ipgad")
|
||||||
|
|
||||||
|
[sub_resource type="QuadMesh" id="QuadMesh_0x06e"]
|
||||||
|
size = Vector2(0.5, 1)
|
||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwbye"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwbye"]
|
||||||
radius = 0.3
|
radius = 0.3
|
||||||
height = 0.8
|
height = 0.8
|
||||||
|
|
||||||
[node name="Sprout" type="Node3D" node_paths=PackedStringArray("_need_water_drop", "_production_timer", "_sprite")]
|
[node name="Sprout" type="Node3D" node_paths=PackedStringArray("_need_water_drop", "_production_timer", "_mesh", "_area")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00401986, -0.00383317, 0.00119042)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00401986, -0.00383317, 0.00119042)
|
||||||
script = ExtResource("1_snma1")
|
script = ExtResource("1_snma1")
|
||||||
_need_water_drop = NodePath("NeedWaterDrop")
|
_need_water_drop = NodePath("NeedWaterDrop")
|
||||||
_production_timer = NodePath("ProductionTimer")
|
_production_timer = NodePath("ProductionTimer")
|
||||||
_sprite = NodePath("Sprite3D")
|
_mesh = NodePath("Mesh")
|
||||||
|
_area = NodePath("Area3D")
|
||||||
|
|
||||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
replication_config = SubResource("SceneReplicationConfig_rs2qp")
|
replication_config = SubResource("SceneReplicationConfig_rs2qp")
|
||||||
|
|
||||||
[node name="Sprite3D" type="Sprite3D" parent="."]
|
[node name="Mesh" type="MeshInstance3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0)
|
||||||
pixel_size = 0.02
|
material_override = SubResource("ShaderMaterial_3ul7y")
|
||||||
billboard = 2
|
mesh = SubResource("QuadMesh_0x06e")
|
||||||
shaded = true
|
|
||||||
texture_filter = 2
|
|
||||||
texture = ExtResource("2_ipgad")
|
|
||||||
|
|
||||||
[node name="NeedWaterDrop" type="Sprite3D" parent="."]
|
[node name="NeedWaterDrop" type="Sprite3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3, 0)
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
extends CanvasLayer
|
extends CanvasLayer
|
||||||
|
|
||||||
@export var _combo_timer: Timer
|
@export var _combo_timer: Timer
|
||||||
|
@export var _combo_label: RichTextLabel
|
||||||
|
|
||||||
var _id: int
|
var _id: int
|
||||||
|
var _last_combo_time: float
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var blend := Color(0.2, 0.2, 0.2, (Time.get_ticks_msec() - _last_combo_time) / 3000)
|
||||||
|
var color := Color.GOLD.blend(blend)
|
||||||
|
_combo_label.add_theme_color_override("default_color", color)
|
||||||
|
_combo_label.self_modulate = Color(1, 1, 1,
|
||||||
|
clamp(1 - (Time.get_ticks_msec() - _last_combo_time) / 3000, 0, 1))
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -10,14 +19,15 @@ func _ready() -> void:
|
|||||||
GameState.fetch().player_data[_id].water_combo_update.connect(
|
GameState.fetch().player_data[_id].water_combo_update.connect(
|
||||||
func(current: int):
|
func(current: int):
|
||||||
if current == 0:
|
if current == 0:
|
||||||
$Combo.hide()
|
_combo_label.hide()
|
||||||
else:
|
else:
|
||||||
$Combo.show()
|
_combo_label.show()
|
||||||
$Combo.text = "+" + str(current) + "!"
|
_combo_label.text = "+" + str(current) + "!"
|
||||||
|
_last_combo_time = Time.get_ticks_msec()
|
||||||
_combo_timer.start()
|
_combo_timer.start()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func _on_combo_timer_timeout() -> void:
|
func _on_combo_timer_timeout() -> void:
|
||||||
GameState.fetch().player_data[_id].reset_water_combo()
|
GameState.fetch().player_data[_id].reset_water_combo()
|
||||||
$Combo.hide()
|
_combo_label.hide()
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
extends Node3D
|
|
||||||
|
|
||||||
@export var _splash_small_sound: AudioStreamPlayer3D
|
|
||||||
@export var _splash_small_quiet_sound: AudioStreamPlayer3D
|
|
||||||
@export var _model: Node3D
|
|
||||||
@export var _splash_particles: GPUParticles3D
|
|
||||||
@export var _picking_area: Area3D
|
|
||||||
@export var body: RigidBody3D
|
|
||||||
## no longer exists and shouldn't be considered, but not ready to be freed yet
|
|
||||||
@export var is_dead := false
|
|
||||||
|
|
||||||
var _in_splash_range := {}
|
|
||||||
|
|
||||||
## something to ignore
|
|
||||||
var sender_id: int
|
|
||||||
var sender_body: PhysicsBody3D
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
body.process_mode = Node.PROCESS_MODE_DISABLED
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
if not is_multiplayer_authority():
|
|
||||||
return
|
|
||||||
|
|
||||||
global_position = body.global_position
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
|
||||||
func _disable_body() -> void:
|
|
||||||
# not using synchronizer for this because it ends up enabling processing
|
|
||||||
# on other clients
|
|
||||||
(func() -> void: body.process_mode = Node.PROCESS_MODE_DISABLED).call_deferred()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_body_entered(p_body: Node3D) -> void:
|
|
||||||
if p_body == sender_body:
|
|
||||||
return
|
|
||||||
|
|
||||||
if p_body.is_in_group("voids"):
|
|
||||||
queue_free()
|
|
||||||
return
|
|
||||||
|
|
||||||
for area: Area3D in _in_splash_range:
|
|
||||||
area.get_parent_node_3d().water.rpc_id(1, sender_id)
|
|
||||||
|
|
||||||
_splash_small_sound.play()
|
|
||||||
_splash_small_quiet_sound.play()
|
|
||||||
_splash_particles.emitting = true
|
|
||||||
|
|
||||||
is_dead = true
|
|
||||||
_model.hide()
|
|
||||||
_picking_area.collision_layer = 0
|
|
||||||
_disable_body.rpc()
|
|
||||||
_picking_area.collision_layer = 0
|
|
||||||
await _splash_small_sound.finished
|
|
||||||
if _splash_small_quiet_sound.playing:
|
|
||||||
await _splash_small_quiet_sound.finished
|
|
||||||
queue_free()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_splash_area_entered(area: Area3D) -> void:
|
|
||||||
_in_splash_range[area] = true
|
|
||||||
|
|
||||||
|
|
||||||
func _on_splash_area_exited(area: Area3D) -> void:
|
|
||||||
_in_splash_range.erase(area)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
|
||||||
func set_global_pos(new: Vector3) -> void:
|
|
||||||
global_position = new
|
|
||||||
body.global_position = new
|
|
||||||
body.reset_physics_interpolation()
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
|
||||||
func get_picked_up() -> void:
|
|
||||||
if is_multiplayer_authority():
|
|
||||||
queue_free()
|
|
||||||
|
|
||||||
|
|
||||||
func mark_interactive() -> void:
|
|
||||||
($Model as CSGSphere3D).material_override.next_pass.set("shader_parameter/color", Color.WHITE)
|
|
||||||
|
|
||||||
|
|
||||||
func mark_non_interactive() -> void:
|
|
||||||
($Model as CSGSphere3D).material_override.next_pass.set("shader_parameter/color", Color(1, 1, 1, 0))
|
|
@ -1,11 +1,9 @@
|
|||||||
[gd_scene load_steps=15 format=3 uid="uid://tdsbo3e5ic86"]
|
[gd_scene load_steps=11 format=3 uid="uid://tdsbo3e5ic86"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/water_bomb.gd" id="1_lk5fq"]
|
[ext_resource type="Script" path="res://src/ingame/bomb.gd" id="1_lk5fq"]
|
||||||
[ext_resource type="PackedScene" uid="uid://s2a1pry5fw8f" path="res://scenes/water_bomb_model.tscn" id="2_0lxuq"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://dtjpv2b74g24m" path="res://assets/sfx/splash-small.wav" id="2_0wk8g"]
|
[ext_resource type="AudioStream" uid="uid://dtjpv2b74g24m" path="res://assets/sfx/splash-small.wav" id="2_0wk8g"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ba2mut58elwrh" path="res://assets/water-bomb.glb" id="2_v2imr"]
|
||||||
[ext_resource type="AudioStream" uid="uid://blgrl2wl05feq" path="res://assets/sfx/splash-small-quiet.wav" id="3_hgy7l"]
|
[ext_resource type="AudioStream" uid="uid://blgrl2wl05feq" path="res://assets/sfx/splash-small-quiet.wav" id="3_hgy7l"]
|
||||||
[ext_resource type="Shader" path="res://scenes/interactivity_outline.gdshader" id="3_vfl1p"]
|
|
||||||
[ext_resource type="Script" path="res://src/lib/item_component.gd" id="5_rpnf2"]
|
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_0ebrr"]
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_0ebrr"]
|
||||||
properties/0/path = NodePath(".:position")
|
properties/0/path = NodePath(".:position")
|
||||||
@ -26,20 +24,9 @@ properties/4/replication_mode = 2
|
|||||||
properties/5/path = NodePath("SplashParticles:emitting")
|
properties/5/path = NodePath("SplashParticles:emitting")
|
||||||
properties/5/spawn = true
|
properties/5/spawn = true
|
||||||
properties/5/replication_mode = 2
|
properties/5/replication_mode = 2
|
||||||
|
properties/6/path = NodePath(".:rotation")
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_cpgfr"]
|
properties/6/spawn = true
|
||||||
resource_local_to_scene = true
|
properties/6/replication_mode = 1
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("3_vfl1p")
|
|
||||||
shader_parameter/color = Color(1, 1, 1, 0)
|
|
||||||
shader_parameter/size = 1.24
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dykfn"]
|
|
||||||
resource_local_to_scene = true
|
|
||||||
next_pass = SubResource("ShaderMaterial_cpgfr")
|
|
||||||
albedo_color = Color(0.0936238, 0.825356, 1, 1)
|
|
||||||
metallic = 0.8
|
|
||||||
roughness = 0.4
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_v7dnr"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_v7dnr"]
|
||||||
albedo_color = Color(0, 1, 1, 1)
|
albedo_color = Color(0, 1, 1, 1)
|
||||||
@ -70,12 +57,15 @@ _model = NodePath("Model")
|
|||||||
_splash_particles = NodePath("SplashParticles")
|
_splash_particles = NodePath("SplashParticles")
|
||||||
_picking_area = NodePath("PickingArea")
|
_picking_area = NodePath("PickingArea")
|
||||||
body = NodePath("RigidBody3D")
|
body = NodePath("RigidBody3D")
|
||||||
|
item_id = &"water_bomb"
|
||||||
|
item_count = 1
|
||||||
|
splash_function = "water"
|
||||||
|
|
||||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
replication_config = SubResource("SceneReplicationConfig_0ebrr")
|
replication_config = SubResource("SceneReplicationConfig_0ebrr")
|
||||||
|
|
||||||
[node name="Model" parent="." instance=ExtResource("2_0lxuq")]
|
[node name="Model" parent="." instance=ExtResource("2_v2imr")]
|
||||||
material_override = SubResource("StandardMaterial3D_dykfn")
|
transform = Transform3D(-0.994881, 0, -0.101056, 0, 1, 0, 0.101056, 0, -0.994881, 0, 0, 0)
|
||||||
|
|
||||||
[node name="SplashParticles" type="GPUParticles3D" parent="."]
|
[node name="SplashParticles" type="GPUParticles3D" parent="."]
|
||||||
material_override = SubResource("StandardMaterial3D_v7dnr")
|
material_override = SubResource("StandardMaterial3D_v7dnr")
|
||||||
@ -124,10 +114,6 @@ monitoring = false
|
|||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="PickingArea"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="PickingArea"]
|
||||||
shape = SubResource("SphereShape3D_6c830")
|
shape = SubResource("SphereShape3D_6c830")
|
||||||
|
|
||||||
[node name="ItemComponent" type="Node" parent="."]
|
|
||||||
script = ExtResource("5_rpnf2")
|
|
||||||
id = "water"
|
|
||||||
|
|
||||||
[connection signal="body_entered" from="RigidBody3D" to="." method="_on_body_entered"]
|
[connection signal="body_entered" from="RigidBody3D" to="." method="_on_body_entered"]
|
||||||
[connection signal="area_entered" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_entered"]
|
[connection signal="area_entered" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_entered"]
|
||||||
[connection signal="area_exited" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_exited"]
|
[connection signal="area_exited" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_exited"]
|
||||||
|
@ -1,7 +1,18 @@
|
|||||||
class_name GameState
|
class_name GameState extends Resource
|
||||||
extends Resource
|
|
||||||
|
|
||||||
|
# TODO: build dynamically?
|
||||||
|
var INVENTORY_ITEM_DB := {
|
||||||
|
&"meat": load("res://data/meat.tres"),
|
||||||
|
&"water_bomb": load("res://data/water_bomb.tres"),
|
||||||
|
&"coin_flower": load("res://data/coin_flower.tres"),
|
||||||
|
&"coin": load("res://data/coin.tres"),
|
||||||
|
}
|
||||||
|
|
||||||
|
## keys are multiplayer ID ints, values are PlayerData
|
||||||
@export var player_data := {}
|
@export var player_data := {}
|
||||||
|
## keys are InventoryItem resource IDs (from db),
|
||||||
|
## values are { "item": InventoryItem, "count": int }
|
||||||
|
@export var inventory := {}
|
||||||
|
|
||||||
static var _instance := GameState.new()
|
static var _instance := GameState.new()
|
||||||
|
|
||||||
@ -12,3 +23,25 @@ static func save() -> void:
|
|||||||
|
|
||||||
static func fetch() -> GameState:
|
static func fetch() -> GameState:
|
||||||
return _instance
|
return _instance
|
||||||
|
|
||||||
|
|
||||||
|
static func get_item_count(p_item_id: StringName) -> int:
|
||||||
|
if GameState.fetch().inventory.has(p_item_id):
|
||||||
|
return GameState.fetch().inventory[p_item_id]["count"]
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: better place for those?
|
||||||
|
static func are_bundles_stackable(p_a_bundle: Dictionary, p_b_bundle: Dictionary) -> bool:
|
||||||
|
var item = GameState.fetch().INVENTORY_ITEM_DB[p_a_bundle["item_id"]]
|
||||||
|
return p_a_bundle["item_id"] == p_b_bundle["item_id"] and \
|
||||||
|
item.stackable and p_a_bundle["count"] + p_b_bundle["count"] <= item.stack_limit
|
||||||
|
|
||||||
|
|
||||||
|
static func combine_bundles(p_a_bundle: Dictionary, p_b_bundle: Dictionary) -> Dictionary:
|
||||||
|
assert(are_bundles_stackable(p_a_bundle, p_b_bundle))
|
||||||
|
return {
|
||||||
|
"item_id": p_a_bundle["item_id"],
|
||||||
|
"count": p_a_bundle["count"] + p_b_bundle["count"],
|
||||||
|
}
|
||||||
|
12
src/lib/inventory_item.gd
Normal file
12
src/lib/inventory_item.gd
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class_name InventoryItem extends Resource
|
||||||
|
|
||||||
|
@export var icon: Texture2D = preload("res://icon.svg")
|
||||||
|
@export var model: PackedScene
|
||||||
|
@export var bomb: PackedScene = preload("res://src/ingame/item_bomb.tscn")
|
||||||
|
@export var name := "NAME"
|
||||||
|
@export var id := &"ID"
|
||||||
|
|
||||||
|
@export var stackable := false
|
||||||
|
@export var stack_limit := 8
|
||||||
|
|
||||||
|
@export var sells_for := 0
|
@ -1,17 +0,0 @@
|
|||||||
class_name ItemComponent
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
## Base identity, properties are defined in item db.
|
|
||||||
@export var id: String
|
|
||||||
|
|
||||||
|
|
||||||
func mark_interactive() -> void:
|
|
||||||
var parent := get_parent()
|
|
||||||
if parent.has_method("mark_interactive"):
|
|
||||||
parent.mark_interactive()
|
|
||||||
|
|
||||||
|
|
||||||
func mark_non_interactive(delta: float) -> void:
|
|
||||||
var parent := get_parent()
|
|
||||||
if parent.has_method("mark_non_interactive"):
|
|
||||||
parent.mark_non_interactive()
|
|
156
src/lib/player_character.gd
Normal file
156
src/lib/player_character.gd
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
class_name StairStepper extends Node
|
||||||
|
# MIT License
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 JKWall
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
## Credits:
|
||||||
|
# Special thanks to Majikayo Games for original solution to stair_step_down!
|
||||||
|
# (https://youtu.be/-WjM1uksPIk)
|
||||||
|
#
|
||||||
|
# Special thanks to Myria666 for their paper on Quake movement mechanics (used for stair_step_up)!
|
||||||
|
# (https://github.com/myria666/qMovementDoc)
|
||||||
|
#
|
||||||
|
# Special thanks to Andicraft for their help with implementation stair_step_up!
|
||||||
|
# (https://github.com/Andicraft)
|
||||||
|
|
||||||
|
## Notes:
|
||||||
|
# 0. All shape colliders are supported. Although, I would recommend Capsule colliders for enemies
|
||||||
|
# as it works better with the Navigation Meshes. Its up to you what shape you want to use
|
||||||
|
# for players.
|
||||||
|
#
|
||||||
|
# 1. To adjust the step-up/down height, just change the MAX_STEP_UP/MAX_STEP_DOWN values below.
|
||||||
|
#
|
||||||
|
# 2. This uses Jolt Physics as the default Godot Physics has a few bugs:
|
||||||
|
# 1: Small gaps that you should be able to fit through both ways will block you in Godot Physics.
|
||||||
|
# You can see this demonstrated with the floating boxes in front of the big stairs.
|
||||||
|
# 2: Walking into some objects may push the player downward by a small amount which causes
|
||||||
|
# jittering and causes the floor to be detected as a step.
|
||||||
|
# TLDR: This still works with default Godot Physics, although it feels a lot better in Jolt Physics.
|
||||||
|
|
||||||
|
@export var MAX_STEP_UP := 0.5 # Maximum height in meters the player can step up.
|
||||||
|
@export var MAX_STEP_DOWN := -0.5 # Maximum height in meters the player can step down.
|
||||||
|
|
||||||
|
var was_grounded: bool = true
|
||||||
|
var is_grounded: bool = true
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(_delta: float) -> void:
|
||||||
|
was_grounded = is_grounded
|
||||||
|
is_grounded = owner.is_on_floor()
|
||||||
|
|
||||||
|
|
||||||
|
# Function: Handle walking down stairs
|
||||||
|
func stair_step_down():
|
||||||
|
if owner.is_on_floor():
|
||||||
|
return
|
||||||
|
|
||||||
|
# If we're falling from a step
|
||||||
|
if owner.velocity.y <= 0 and was_grounded:
|
||||||
|
# Initialize body test variables
|
||||||
|
var body_test_result = PhysicsTestMotionResult3D.new()
|
||||||
|
var body_test_params = PhysicsTestMotionParameters3D.new()
|
||||||
|
|
||||||
|
body_test_params.from = owner.global_transform ## We get the player's current global_transform
|
||||||
|
body_test_params.motion = Vector3(0, MAX_STEP_DOWN, 0) ## We project the player downward
|
||||||
|
|
||||||
|
if PhysicsServer3D.body_test_motion(owner.get_rid(), body_test_params, body_test_result):
|
||||||
|
# Enters if a collision is detected by body_test_motion
|
||||||
|
# Get distance to step and move player downward by that much
|
||||||
|
owner.position.y += body_test_result.get_travel().y
|
||||||
|
owner.apply_floor_snap()
|
||||||
|
is_grounded = true
|
||||||
|
|
||||||
|
|
||||||
|
# Function: Handle walking up stairs
|
||||||
|
func stair_step_up(wish_dir: Vector3):
|
||||||
|
if wish_dir == Vector3.ZERO:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 0. Initialize testing variables
|
||||||
|
var body_test_params = PhysicsTestMotionParameters3D.new()
|
||||||
|
var body_test_result = PhysicsTestMotionResult3D.new()
|
||||||
|
|
||||||
|
var test_transform = owner.global_transform ## Storing current global_transform for testing
|
||||||
|
var distance = wish_dir * 0.1 ## Distance forward we want to check
|
||||||
|
body_test_params.from = owner.global_transform ## Self as origin point
|
||||||
|
body_test_params.motion = distance ## Go forward by current distance
|
||||||
|
|
||||||
|
# Pre-check: Are we colliding?
|
||||||
|
if !PhysicsServer3D.body_test_motion(owner.get_rid(), body_test_params, body_test_result):
|
||||||
|
## If we don't collide, return
|
||||||
|
return
|
||||||
|
|
||||||
|
# 1. Move test_transform to collision location
|
||||||
|
var remainder = body_test_result.get_remainder() ## Get remainder from collision
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel()) ## Move test_transform by distance traveled before collision
|
||||||
|
|
||||||
|
# 2. Move test_transform up to ceiling (if any)
|
||||||
|
var step_up = MAX_STEP_UP * Vector3.UP
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = step_up
|
||||||
|
PhysicsServer3D.body_test_motion(owner.get_rid(), body_test_params, body_test_result)
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 3. Move test_transform forward by remaining distance
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = remainder
|
||||||
|
PhysicsServer3D.body_test_motion(owner.get_rid(), body_test_params, body_test_result)
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 3.5 Project remaining along wall normal (if any)
|
||||||
|
## So you can walk into wall and up a step
|
||||||
|
if body_test_result.get_collision_count() != 0:
|
||||||
|
remainder = body_test_result.get_remainder().length()
|
||||||
|
|
||||||
|
### Uh, there may be a better way to calculate this in Godot.
|
||||||
|
var wall_normal = body_test_result.get_collision_normal()
|
||||||
|
var dot_div_mag = wish_dir.dot(wall_normal) / (wall_normal * wall_normal).length()
|
||||||
|
var projected_vector = (wish_dir - dot_div_mag * wall_normal).normalized()
|
||||||
|
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = remainder * projected_vector
|
||||||
|
PhysicsServer3D.body_test_motion(owner.get_rid(), body_test_params, body_test_result)
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 4. Move test_transform down onto step
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = MAX_STEP_UP * -Vector3.UP
|
||||||
|
|
||||||
|
# Return if no collision
|
||||||
|
if !PhysicsServer3D.body_test_motion(owner.get_rid(), body_test_params, body_test_result):
|
||||||
|
return
|
||||||
|
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 5. Check floor normal for un-walkable slope
|
||||||
|
var surface_normal = body_test_result.get_collision_normal()
|
||||||
|
var temp_floor_max_angle = owner.floor_max_angle + deg_to_rad(20)
|
||||||
|
if (snappedf(surface_normal.angle_to(Vector3.UP), 0.001) > temp_floor_max_angle):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# 6. Move player up
|
||||||
|
var global_pos = owner.global_position
|
||||||
|
#var step_up_dist = test_transform.origin.y - global_pos.y
|
||||||
|
|
||||||
|
global_pos.y = test_transform.origin.y
|
||||||
|
owner.global_position = global_pos
|
@ -5,6 +5,7 @@ extends Resource
|
|||||||
|
|
||||||
## How many plants are watered in a time window.
|
## How many plants are watered in a time window.
|
||||||
var _water_combo: int
|
var _water_combo: int
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
signal water_combo_update(current: int)
|
signal water_combo_update(current: int)
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +35,9 @@ func _on_player_joined(id: int) -> void:
|
|||||||
_register_player.rpc_id(id, username)
|
_register_player.rpc_id(id, username)
|
||||||
|
|
||||||
if _game_started:
|
if _game_started:
|
||||||
|
for item_id in GameState.fetch().inventory:
|
||||||
|
set_inventory_item_count.rpc_id(id, item_id, GameState.fetch().inventory[item_id].count)
|
||||||
|
|
||||||
_start_game.rpc_id(id)
|
_start_game.rpc_id(id)
|
||||||
|
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ func _add_chat_message(username: String, text: String) -> void:
|
|||||||
|
|
||||||
# keep chat scrolled to the bottom
|
# keep chat scrolled to the bottom
|
||||||
await _chat_history_scroll.get_v_scroll_bar().changed
|
await _chat_history_scroll.get_v_scroll_bar().changed
|
||||||
_chat_history_scroll.scroll_vertical = _chat_history_scroll.get_v_scroll_bar().max_value
|
_chat_history_scroll.scroll_vertical = int(_chat_history_scroll.get_v_scroll_bar().max_value)
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
@ -173,3 +176,39 @@ func _on_chat_message_submitted(text := "") -> void:
|
|||||||
|
|
||||||
_submit_chat_message.rpc_id(1, _chat_input.text)
|
_submit_chat_message.rpc_id(1, _chat_input.text)
|
||||||
_chat_input.clear()
|
_chat_input.clear()
|
||||||
|
|
||||||
|
|
||||||
|
## Make sure it exists and all.
|
||||||
|
func prepate_inventory_idem(item_id: StringName) -> void:
|
||||||
|
if not GameState.fetch().inventory.has(item_id):
|
||||||
|
GameState.fetch().inventory[item_id] = {
|
||||||
|
"item": GameState.fetch().INVENTORY_ITEM_DB[item_id],
|
||||||
|
"count": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: made any_peer to have access from projectiles
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func add_inventory_item(item_id: StringName, amount: int) -> void:
|
||||||
|
prepate_inventory_idem(item_id)
|
||||||
|
GameState.fetch().inventory[item_id]["count"] += amount
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func remove_inventory_item(item_id: StringName, amount: int) -> void:
|
||||||
|
assert(GameState.fetch().inventory.has(item_id))
|
||||||
|
|
||||||
|
GameState.fetch().inventory[item_id]["count"] -= amount
|
||||||
|
assert(GameState.fetch().inventory[item_id]["count"] >= 0)
|
||||||
|
|
||||||
|
if GameState.fetch().inventory[item_id]["count"] == 0:
|
||||||
|
GameState.fetch().inventory.erase(item_id)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func set_inventory_item_count(item_id: StringName, value: int) -> void:
|
||||||
|
prepate_inventory_idem(item_id)
|
||||||
|
GameState.fetch().inventory[item_id]["count"] = value
|
||||||
|
|
||||||
|
if GameState.fetch().inventory[item_id]["count"] == 0:
|
||||||
|
GameState.fetch().inventory.erase(item_id)
|
||||||
|
Reference in New Issue
Block a user