generated from krampus/template-godot4
Compare commits
3 Commits
b3af967745
...
980efdb5e6
Author | SHA1 | Date | |
---|---|---|---|
980efdb5e6 | |||
3d1e5dda38 | |||
ff379484ca |
Binary file not shown.
BIN
assets/stickers/glowing_star_3d.png
(Stored with Git LFS)
Normal file
BIN
assets/stickers/glowing_star_3d.png
(Stored with Git LFS)
Normal file
Binary file not shown.
34
assets/stickers/glowing_star_3d.png.import
Normal file
34
assets/stickers/glowing_star_3d.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dsrm2mw4e4gx1"
|
||||||
|
path="res://.godot/imported/glowing_star_3d.png-5114e5219616e1224c3af11f20cc8171.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/stickers/glowing_star_3d.png"
|
||||||
|
dest_files=["res://.godot/imported/glowing_star_3d.png-5114e5219616e1224c3af11f20cc8171.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
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/stickers/heart_suit_3d.png
(Stored with Git LFS)
Normal file
BIN
assets/stickers/heart_suit_3d.png
(Stored with Git LFS)
Normal file
Binary file not shown.
34
assets/stickers/heart_suit_3d.png.import
Normal file
34
assets/stickers/heart_suit_3d.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cl8ui8nnoaa1i"
|
||||||
|
path="res://.godot/imported/heart_suit_3d.png-13871ac315a96fa440a66ea89478611e.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/stickers/heart_suit_3d.png"
|
||||||
|
dest_files=["res://.godot/imported/heart_suit_3d.png-13871ac315a96fa440a66ea89478611e.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
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/stickers/hundred_points_3d.png
(Stored with Git LFS)
Normal file
BIN
assets/stickers/hundred_points_3d.png
(Stored with Git LFS)
Normal file
Binary file not shown.
34
assets/stickers/hundred_points_3d.png.import
Normal file
34
assets/stickers/hundred_points_3d.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ck6n427v1uh4m"
|
||||||
|
path="res://.godot/imported/hundred_points_3d.png-60516c05d8945ed8a9024154cfc0db6b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/stickers/hundred_points_3d.png"
|
||||||
|
dest_files=["res://.godot/imported/hundred_points_3d.png-60516c05d8945ed8a9024154cfc0db6b.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
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/stickers/rolling_on_the_floor_laughing_3d.png
(Stored with Git LFS)
Normal file
BIN
assets/stickers/rolling_on_the_floor_laughing_3d.png
(Stored with Git LFS)
Normal file
Binary file not shown.
34
assets/stickers/rolling_on_the_floor_laughing_3d.png.import
Normal file
34
assets/stickers/rolling_on_the_floor_laughing_3d.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dgoceatem5kd4"
|
||||||
|
path="res://.godot/imported/rolling_on_the_floor_laughing_3d.png-80f304d04a0b0e7474c7719f656ead4a.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/stickers/rolling_on_the_floor_laughing_3d.png"
|
||||||
|
dest_files=["res://.godot/imported/rolling_on_the_floor_laughing_3d.png-80f304d04a0b0e7474c7719f656ead4a.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
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/ui/hud/tools/hand_bg.png
(Stored with Git LFS)
Normal file
BIN
assets/ui/hud/tools/hand_bg.png
(Stored with Git LFS)
Normal file
Binary file not shown.
34
assets/ui/hud/tools/hand_bg.png.import
Normal file
34
assets/ui/hud/tools/hand_bg.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://db85cfwlticnb"
|
||||||
|
path="res://.godot/imported/hand_bg.png-dba561c746d5d9d7eda16967a74a41dd.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/ui/hud/tools/hand_bg.png"
|
||||||
|
dest_files=["res://.godot/imported/hand_bg.png-dba561c746d5d9d7eda16967a74a41dd.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
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/ui/hud/tools/hand_fg.png
(Stored with Git LFS)
Normal file
BIN
assets/ui/hud/tools/hand_fg.png
(Stored with Git LFS)
Normal file
Binary file not shown.
34
assets/ui/hud/tools/hand_fg.png.import
Normal file
34
assets/ui/hud/tools/hand_fg.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cju4oxjgaf0ee"
|
||||||
|
path="res://.godot/imported/hand_fg.png-9b58f7a1a95a5390121469b6f08ef067.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/ui/hud/tools/hand_fg.png"
|
||||||
|
dest_files=["res://.godot/imported/hand_fg.png-9b58f7a1a95a5390121469b6f08ef067.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
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
|
@ -180,11 +180,16 @@ select_mp3_player={
|
|||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":52,"key_label":0,"unicode":52,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":52,"key_label":0,"unicode":52,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
select_manual={
|
select_stickers={
|
||||||
"deadzone": 0.2,
|
"deadzone": 0.2,
|
||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":53,"key_label":0,"unicode":53,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":53,"key_label":0,"unicode":53,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
select_manual={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":48,"key_label":0,"unicode":48,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
pause={
|
pause={
|
||||||
"deadzone": 0.2,
|
"deadzone": 0.2,
|
||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
@ -34,6 +34,7 @@ anchor_right = 0.5
|
|||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
[node name="DeviceTexture" type="TextureRect" parent="HUDTool/Rumbler/Position/HUDElement"]
|
[node name="DeviceTexture" type="TextureRect" parent="HUDTool/Rumbler/Position/HUDElement"]
|
||||||
texture_filter = 1
|
texture_filter = 1
|
||||||
@ -44,6 +45,7 @@ offset_right = -162.0
|
|||||||
offset_bottom = 25.0
|
offset_bottom = 25.0
|
||||||
scale = Vector2(5, 5)
|
scale = Vector2(5, 5)
|
||||||
texture = ExtResource("3_de88k")
|
texture = ExtResource("3_de88k")
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
[node name="DeviceScreenMask" type="TextureRect" parent="HUDTool/Rumbler/Position/HUDElement"]
|
[node name="DeviceScreenMask" type="TextureRect" parent="HUDTool/Rumbler/Position/HUDElement"]
|
||||||
clip_children = 1
|
clip_children = 1
|
||||||
|
@ -20,5 +20,5 @@ func _spray() -> void:
|
|||||||
(collider as GunkBody).paint_continuous(
|
(collider as GunkBody).paint_continuous(
|
||||||
point, laser.get_collision_normal(), point_scale
|
point, laser.get_collision_normal(), point_scale
|
||||||
)
|
)
|
||||||
if collider is GunkNode:
|
if collider is Sprayable:
|
||||||
(collider as GunkNode).hit(damage)
|
(collider as Sprayable).hit(damage)
|
||||||
|
12
src/equipment/sprayable.gd
Normal file
12
src/equipment/sprayable.gd
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class_name Sprayable extends StaticBody3D
|
||||||
|
|
||||||
|
|
||||||
|
## Called each frame this node takes a hit.
|
||||||
|
##
|
||||||
|
## Derived types should override `_hit()` as a lifecycle method.
|
||||||
|
func hit(damage: float) -> void:
|
||||||
|
_hit()
|
||||||
|
|
||||||
|
|
||||||
|
func _hit() -> void:
|
||||||
|
pass # Implemented in derived type
|
1
src/equipment/sprayable.gd.uid
Normal file
1
src/equipment/sprayable.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://ddpgqjf71eqm5
|
85
src/equipment/sticker_pack/sticker_pack.gd
Normal file
85
src/equipment/sticker_pack/sticker_pack.gd
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
extends SurfaceSnapTool
|
||||||
|
|
||||||
|
const USER_STICKER_PATH := "user://stickers"
|
||||||
|
|
||||||
|
const RUMBLE_INTENSITY = 0.0009
|
||||||
|
const RUMBLE_DROPOFF = 0.8
|
||||||
|
|
||||||
|
@export var builtin_stickers: Array[Texture2D] = []
|
||||||
|
@export var selection_idx: int = 0:
|
||||||
|
set = _set_selection_idx
|
||||||
|
|
||||||
|
@export_category("Game Scenes")
|
||||||
|
@export var sticker_scene: PackedScene
|
||||||
|
|
||||||
|
var stickers_available: Array[Texture2D]
|
||||||
|
@onready var rumbler: Rumbler3D = %Rumbler
|
||||||
|
@onready var sticker_texture: TextureRect = %StickerTexture
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_import_stickers()
|
||||||
|
_set_selection_idx(0)
|
||||||
|
|
||||||
|
|
||||||
|
func _import_stickers() -> void:
|
||||||
|
print_debug("Loading custom stickers from ", USER_STICKER_PATH)
|
||||||
|
|
||||||
|
var custom_stickers: Array[Texture2D] = []
|
||||||
|
for filename: String in DirAccess.get_files_at(USER_STICKER_PATH):
|
||||||
|
var fullpath := USER_STICKER_PATH.path_join(filename)
|
||||||
|
var image := Image.new()
|
||||||
|
var err := image.load(fullpath)
|
||||||
|
if err != OK:
|
||||||
|
continue
|
||||||
|
custom_stickers.append(ImageTexture.create_from_image(image))
|
||||||
|
print_debug("Loaded custom sticker from ", fullpath)
|
||||||
|
|
||||||
|
stickers_available = builtin_stickers + custom_stickers
|
||||||
|
|
||||||
|
|
||||||
|
func unlocked() -> bool:
|
||||||
|
return World.instance.manager.stickers_unlocked
|
||||||
|
|
||||||
|
|
||||||
|
func get_selected_sticker() -> Texture2D:
|
||||||
|
return stickers_available[selection_idx]
|
||||||
|
|
||||||
|
|
||||||
|
func _set_selection_idx(value: int) -> void:
|
||||||
|
selection_idx = wrapi(value, 0, stickers_available.size())
|
||||||
|
|
||||||
|
sticker_texture.texture = get_selected_sticker()
|
||||||
|
rumbler.intensity = RUMBLE_INTENSITY
|
||||||
|
|
||||||
|
|
||||||
|
func switch_mode() -> void:
|
||||||
|
selection_idx += 1
|
||||||
|
|
||||||
|
|
||||||
|
func fire() -> void:
|
||||||
|
if not firing and raycast.is_colliding():
|
||||||
|
firing = true
|
||||||
|
place_sticker()
|
||||||
|
rumbler.intensity = RUMBLE_INTENSITY
|
||||||
|
|
||||||
|
|
||||||
|
func place_sticker() -> void:
|
||||||
|
var instance: WorldSticker = sticker_scene.instantiate()
|
||||||
|
var target: Node = raycast.get_collider() as Node
|
||||||
|
if not target:
|
||||||
|
push_warning("Tried to apply decal to non-node target ", raycast.get_collider())
|
||||||
|
return
|
||||||
|
target.add_sibling(instance)
|
||||||
|
instance.place(
|
||||||
|
get_selected_sticker(),
|
||||||
|
raycast.get_collision_point(),
|
||||||
|
raycast.get_collision_normal(),
|
||||||
|
global_basis.y
|
||||||
|
)
|
||||||
|
print_debug("Sticker placed")
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
rumbler.intensity *= RUMBLE_DROPOFF
|
||||||
|
super._physics_process(delta)
|
1
src/equipment/sticker_pack/sticker_pack.gd.uid
Normal file
1
src/equipment/sticker_pack/sticker_pack.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bgj4es0w5b30e
|
102
src/equipment/sticker_pack/sticker_pack.tscn
Normal file
102
src/equipment/sticker_pack/sticker_pack.tscn
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
[gd_scene load_steps=11 format=3 uid="uid://cmnokjbv3vuqt"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b274q7uvn0cvp" path="res://src/ui/rumbler_3d.gd" id="1_8t584"]
|
||||||
|
[ext_resource type="Script" uid="uid://bgj4es0w5b30e" path="res://src/equipment/sticker_pack/sticker_pack.gd" id="1_eaw05"]
|
||||||
|
[ext_resource type="Script" uid="uid://dj2x7x5qkbym1" path="res://src/ui/canvas_projector.gd" id="2_vcsmi"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dqc1a8xaqac8h" path="res://src/equipment/sticker_pack/world_sticker.tscn" id="2_yigow"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cl8ui8nnoaa1i" path="res://assets/stickers/heart_suit_3d.png" id="3_8t584"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://db85cfwlticnb" path="res://assets/ui/hud/tools/hand_bg.png" id="3_o1h4s"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dsrm2mw4e4gx1" path="res://assets/stickers/glowing_star_3d.png" id="3_p2skl"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dgoceatem5kd4" path="res://assets/stickers/rolling_on_the_floor_laughing_3d.png" id="4_rw51e"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cju4oxjgaf0ee" path="res://assets/ui/hud/tools/hand_fg.png" id="4_vcsmi"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ck6n427v1uh4m" path="res://assets/stickers/hundred_points_3d.png" id="5_rkig1"]
|
||||||
|
|
||||||
|
[node name="StickerPack" type="Node3D"]
|
||||||
|
script = ExtResource("1_eaw05")
|
||||||
|
builtin_stickers = Array[Texture2D]([ExtResource("3_8t584"), ExtResource("3_p2skl"), ExtResource("4_rw51e"), ExtResource("5_rkig1")])
|
||||||
|
sticker_scene = ExtResource("2_yigow")
|
||||||
|
|
||||||
|
[node name="Raycast" type="RayCast3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.997564, -0.0697565, 0, 0.0697565, 0.997564, 0, 0, -0.15)
|
||||||
|
target_position = Vector3(0, 0, -1)
|
||||||
|
hit_from_inside = true
|
||||||
|
|
||||||
|
[node name="RestingPosition" type="Marker3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.2)
|
||||||
|
|
||||||
|
[node name="HUDTool" type="Node3D" parent="RestingPosition"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.2)
|
||||||
|
top_level = true
|
||||||
|
|
||||||
|
[node name="Rumbler" type="Node3D" parent="RestingPosition/HUDTool"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
script = ExtResource("1_8t584")
|
||||||
|
metadata/_custom_type_script = "uid://b274q7uvn0cvp"
|
||||||
|
|
||||||
|
[node name="CanvasProjector" type="Marker3D" parent="RestingPosition/HUDTool/Rumbler"]
|
||||||
|
script = ExtResource("2_vcsmi")
|
||||||
|
|
||||||
|
[node name="HUDElement" type="Control" parent="RestingPosition/HUDTool/Rumbler/CanvasProjector"]
|
||||||
|
texture_filter = 3
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
|
[node name="HandRoot" type="Control" parent="RestingPosition/HUDTool/Rumbler/CanvasProjector/HUDElement"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -380.0
|
||||||
|
offset_top = -323.0
|
||||||
|
offset_right = -380.0
|
||||||
|
offset_bottom = -323.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="HandBG" type="TextureRect" parent="RestingPosition/HUDTool/Rumbler/CanvasProjector/HUDElement/HandRoot"]
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 128.0
|
||||||
|
offset_bottom = 256.0
|
||||||
|
scale = Vector2(5, 5)
|
||||||
|
texture = ExtResource("3_o1h4s")
|
||||||
|
|
||||||
|
[node name="StickerTexture" type="TextureRect" parent="RestingPosition/HUDTool/Rumbler/CanvasProjector/HUDElement/HandRoot"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = 232.0
|
||||||
|
offset_top = 175.0
|
||||||
|
offset_right = 488.0
|
||||||
|
offset_bottom = 431.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
rotation = -0.139626
|
||||||
|
pivot_offset = Vector2(128, 128)
|
||||||
|
texture = ExtResource("3_8t584")
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
|
[node name="HandFG" type="TextureRect" parent="RestingPosition/HUDTool/Rumbler/CanvasProjector/HUDElement/HandRoot"]
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 128.0
|
||||||
|
offset_bottom = 256.0
|
||||||
|
scale = Vector2(5, 5)
|
||||||
|
texture = ExtResource("4_vcsmi")
|
22
src/equipment/sticker_pack/world_sticker.gd
Normal file
22
src/equipment/sticker_pack/world_sticker.gd
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
class_name WorldSticker extends Sprayable
|
||||||
|
|
||||||
|
@onready var decal: Decal = %Decal
|
||||||
|
|
||||||
|
|
||||||
|
func _hit() -> void:
|
||||||
|
# Remove on hit
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
## Place this sticker at a given point, aligned to the given normal, with the given texture.
|
||||||
|
func place(texture: Texture2D, point: Vector3, normal: Vector3, src_up: Vector3) -> void:
|
||||||
|
decal.texture_albedo = texture
|
||||||
|
global_position = point
|
||||||
|
|
||||||
|
# Build basis
|
||||||
|
var up := -normal
|
||||||
|
var right := up.cross(src_up).normalized()
|
||||||
|
var forward := -right.cross(up).normalized()
|
||||||
|
global_basis = Basis(right, up, forward)
|
||||||
|
|
||||||
|
# TODO handle serialization & deserialization
|
1
src/equipment/sticker_pack/world_sticker.gd.uid
Normal file
1
src/equipment/sticker_pack/world_sticker.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://giosvggx808p
|
41
src/equipment/sticker_pack/world_sticker.tscn
Normal file
41
src/equipment/sticker_pack/world_sticker.tscn
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://dqc1a8xaqac8h"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cl8ui8nnoaa1i" path="res://assets/stickers/heart_suit_3d.png" id="1_e4i3l"]
|
||||||
|
[ext_resource type="Script" uid="uid://giosvggx808p" path="res://src/equipment/sticker_pack/world_sticker.gd" id="1_q766c"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_e4i3l"]
|
||||||
|
radius = 0.09
|
||||||
|
|
||||||
|
[sub_resource type="PlaneMesh" id="PlaneMesh_e4i3l"]
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_e4i3l"]
|
||||||
|
top_radius = 0.01
|
||||||
|
bottom_radius = 0.01
|
||||||
|
height = 0.2
|
||||||
|
|
||||||
|
[node name="WorldSticker" type="StaticBody3D"]
|
||||||
|
collision_layer = 4
|
||||||
|
collision_mask = 0
|
||||||
|
script = ExtResource("1_q766c")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("SphereShape3D_e4i3l")
|
||||||
|
|
||||||
|
[node name="Decal" type="Decal" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
size = Vector3(0.25, 0.1, 0.25)
|
||||||
|
texture_albedo = ExtResource("1_e4i3l")
|
||||||
|
upper_fade = 0.01
|
||||||
|
lower_fade = 0.01
|
||||||
|
|
||||||
|
[node name="DebugPlane" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.729219, -0.68428, 0, 0.68428, 0.729219, 0, 0, 0)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("PlaneMesh_e4i3l")
|
||||||
|
skeleton = NodePath("../Decal")
|
||||||
|
|
||||||
|
[node name="DebugNormal" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.15, 0)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("CylinderMesh_e4i3l")
|
||||||
|
skeleton = NodePath("../Decal")
|
15
src/equipment/surface_snap_tool.gd
Normal file
15
src/equipment/surface_snap_tool.gd
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class_name SurfaceSnapTool extends Tool
|
||||||
|
## A Tool whose HUD component snaps to a surface
|
||||||
|
|
||||||
|
@onready var raycast: RayCast3D = %Raycast
|
||||||
|
@onready var resting_position: Marker3D = %RestingPosition
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
hud_tool.global_basis = global_basis
|
||||||
|
|
||||||
|
var weight := 1 - exp(-hud_accel * delta)
|
||||||
|
var target_position := resting_position.global_position
|
||||||
|
if raycast.is_colliding():
|
||||||
|
target_position = raycast.get_collision_point()
|
||||||
|
hud_tool.global_position = hud_tool.global_position.lerp(target_position, weight)
|
1
src/equipment/surface_snap_tool.gd.uid
Normal file
1
src/equipment/surface_snap_tool.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://c260xr7jpemho
|
@ -1,4 +1,4 @@
|
|||||||
extends Tool
|
extends SurfaceSnapTool
|
||||||
# the wimpy toothbrush
|
# the wimpy toothbrush
|
||||||
|
|
||||||
const PAINT_COLOR := Color(1, 0, 0, 0.3)
|
const PAINT_COLOR := Color(1, 0, 0, 0.3)
|
||||||
@ -6,14 +6,10 @@ const BRUSH_SCALE := 0.2
|
|||||||
|
|
||||||
@export var damage := 0.0063 # ~8 seconds to destroy standard nodule
|
@export var damage := 0.0063 # ~8 seconds to destroy standard nodule
|
||||||
|
|
||||||
@onready var raycast: RayCast3D = %Raycast
|
|
||||||
|
|
||||||
@onready var texture_idle: TextureRect = %TextureIdle
|
@onready var texture_idle: TextureRect = %TextureIdle
|
||||||
@onready var texture_used: TextureRect = %TextureUsed
|
@onready var texture_used: TextureRect = %TextureUsed
|
||||||
@onready var brush_animation: AnimationPlayer = %BrushAnimation
|
@onready var brush_animation: AnimationPlayer = %BrushAnimation
|
||||||
|
|
||||||
@onready var resting_position: Marker3D = %RestingPosition
|
|
||||||
|
|
||||||
|
|
||||||
func unlocked() -> bool:
|
func unlocked() -> bool:
|
||||||
return World.instance.manager.toothbrush_unlocked
|
return World.instance.manager.toothbrush_unlocked
|
||||||
@ -42,13 +38,3 @@ func _fire() -> void:
|
|||||||
func _idle() -> void:
|
func _idle() -> void:
|
||||||
texture_idle.visible = true
|
texture_idle.visible = true
|
||||||
texture_used.visible = false
|
texture_used.visible = false
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
|
||||||
hud_tool.global_basis = global_basis
|
|
||||||
|
|
||||||
var weight := 1 - exp(-hud_accel * delta)
|
|
||||||
var target_position := resting_position.global_position
|
|
||||||
if raycast.is_colliding():
|
|
||||||
target_position = raycast.get_collision_point()
|
|
||||||
hud_tool.global_position = hud_tool.global_position.lerp(target_position, weight)
|
|
||||||
|
@ -61,8 +61,8 @@ func _spray() -> void:
|
|||||||
prev_target = target
|
prev_target = target
|
||||||
prev_point = point
|
prev_point = point
|
||||||
prev_normal = normal
|
prev_normal = normal
|
||||||
elif collider is GunkNode:
|
elif collider is Sprayable:
|
||||||
(collider as GunkNode).hit(damage)
|
(collider as Sprayable).hit(damage)
|
||||||
|
|
||||||
|
|
||||||
func _on_animation_finished(anim_name: StringName) -> void:
|
func _on_animation_finished(anim_name: StringName) -> void:
|
||||||
|
@ -63,6 +63,7 @@ var _was_on_floor := false
|
|||||||
@onready var wide_spray: WideSpray = %WideSpray
|
@onready var wide_spray: WideSpray = %WideSpray
|
||||||
@onready var toothbrush: Tool = %Toothbrush
|
@onready var toothbrush: Tool = %Toothbrush
|
||||||
@onready var mp3_player: Tool = %MP3Player
|
@onready var mp3_player: Tool = %MP3Player
|
||||||
|
@onready var sticker_pack: Tool = %StickerPack
|
||||||
|
|
||||||
@onready var crouch_head_area: Area3D = %CrouchHeadArea
|
@onready var crouch_head_area: Area3D = %CrouchHeadArea
|
||||||
@onready var crouch_animation: AnimationPlayer = %CrouchAnimation
|
@onready var crouch_animation: AnimationPlayer = %CrouchAnimation
|
||||||
@ -173,7 +174,7 @@ func _on_milestone(milestone: Milestone) -> void:
|
|||||||
if milestone.toothbrush:
|
if milestone.toothbrush:
|
||||||
tool_mount.set_active(toothbrush)
|
tool_mount.set_active(toothbrush)
|
||||||
if milestone.stickers:
|
if milestone.stickers:
|
||||||
pass # TODO equip stickers
|
tool_mount.set_active(sticker_pack)
|
||||||
|
|
||||||
|
|
||||||
func _signal_death() -> void:
|
func _signal_death() -> void:
|
||||||
@ -211,6 +212,8 @@ func _physics_process(delta: float) -> void:
|
|||||||
tool_mount.set_active(toothbrush)
|
tool_mount.set_active(toothbrush)
|
||||||
elif Input.is_action_just_pressed("select_mp3_player"):
|
elif Input.is_action_just_pressed("select_mp3_player"):
|
||||||
tool_mount.set_active(mp3_player)
|
tool_mount.set_active(mp3_player)
|
||||||
|
elif Input.is_action_just_pressed("select_stickers"):
|
||||||
|
tool_mount.set_active(sticker_pack)
|
||||||
|
|
||||||
# Tool use
|
# Tool use
|
||||||
if Input.is_action_pressed("fire"):
|
if Input.is_action_pressed("fire"):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=63 format=3 uid="uid://bwe2jdmvinhqd"]
|
[gd_scene load_steps=64 format=3 uid="uid://bwe2jdmvinhqd"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://buwh0g1ga2aka" path="res://src/player/player.gd" id="1_npueo"]
|
[ext_resource type="Script" uid="uid://buwh0g1ga2aka" path="res://src/player/player.gd" id="1_npueo"]
|
||||||
[ext_resource type="Script" uid="uid://cx1yt0drthpw3" path="res://src/player/camera_controller.gd" id="2_veeqv"]
|
[ext_resource type="Script" uid="uid://cx1yt0drthpw3" path="res://src/player/camera_controller.gd" id="2_veeqv"]
|
||||||
@ -10,6 +10,7 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://c21ksxjyixqe1" path="res://src/equipment/mp3_player/mp3_player.tscn" id="7_e7e1q"]
|
[ext_resource type="PackedScene" uid="uid://c21ksxjyixqe1" path="res://src/equipment/mp3_player/mp3_player.tscn" id="7_e7e1q"]
|
||||||
[ext_resource type="Script" uid="uid://b274q7uvn0cvp" path="res://src/ui/rumbler_3d.gd" id="7_p6grl"]
|
[ext_resource type="Script" uid="uid://b274q7uvn0cvp" path="res://src/ui/rumbler_3d.gd" id="7_p6grl"]
|
||||||
[ext_resource type="Script" uid="uid://b1vyq7e81nyt0" path="res://src/player/headbob_controller.gd" id="7_x42xx"]
|
[ext_resource type="Script" uid="uid://b1vyq7e81nyt0" path="res://src/player/headbob_controller.gd" id="7_x42xx"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cmnokjbv3vuqt" path="res://src/equipment/sticker_pack/sticker_pack.tscn" id="8_xmpm3"]
|
||||||
[ext_resource type="Script" uid="uid://ecrhsueph7at" path="res://src/player/footsteps/footstep_controller.gd" id="9_hja65"]
|
[ext_resource type="Script" uid="uid://ecrhsueph7at" path="res://src/player/footsteps/footstep_controller.gd" id="9_hja65"]
|
||||||
[ext_resource type="Script" uid="uid://brqa2wbtaspw4" path="res://src/player/footsteps/foot_controller.gd" id="9_l271a"]
|
[ext_resource type="Script" uid="uid://brqa2wbtaspw4" path="res://src/player/footsteps/foot_controller.gd" id="9_l271a"]
|
||||||
[ext_resource type="AudioStream" uid="uid://di0e1l1l6l3qc" path="res://assets/sfx/footsteps/metal/metal1.wav" id="10_jcdrv"]
|
[ext_resource type="AudioStream" uid="uid://di0e1l1l6l3qc" path="res://assets/sfx/footsteps/metal/metal1.wav" id="10_jcdrv"]
|
||||||
@ -626,6 +627,10 @@ visible = false
|
|||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
|
[node name="StickerPack" parent="CameraPosition/CameraPivot/ToolMount" instance=ExtResource("8_xmpm3")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
|
||||||
[node name="TransformedPosition" type="Node3D" parent="CameraPosition/CameraPivot"]
|
[node name="TransformedPosition" type="Node3D" parent="CameraPosition/CameraPivot"]
|
||||||
|
|
||||||
[node name="CamRumbler" type="Node3D" parent="CameraPosition/CameraPivot/TransformedPosition"]
|
[node name="CamRumbler" type="Node3D" parent="CameraPosition/CameraPivot/TransformedPosition"]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
class_name GunkNode extends StaticBody3D
|
class_name GunkNode extends Sprayable
|
||||||
## A static body which can be destroyed and collected by the player.
|
## A static body which can be destroyed and collected by the player.
|
||||||
|
|
||||||
## Emitted immediately after this node has been destroyed by the player,
|
## Emitted immediately after this node has been destroyed by the player,
|
||||||
@ -30,7 +30,7 @@ func _enter_tree() -> void:
|
|||||||
func hit(damage: float = 0.05) -> void:
|
func hit(damage: float = 0.05) -> void:
|
||||||
_sustained_damage += damage
|
_sustained_damage += damage
|
||||||
_hit_this_frame = true
|
_hit_this_frame = true
|
||||||
_hit()
|
super.hit(damage)
|
||||||
|
|
||||||
|
|
||||||
## Return this node's current damage as a proportion of it's total durability.
|
## Return this node's current damage as a proportion of it's total durability.
|
||||||
|
@ -4,16 +4,18 @@
|
|||||||
- [x] Clear rate checking / signals
|
- [x] Clear rate checking / signals
|
||||||
- [x] [[nodules]]
|
- [x] [[nodules]]
|
||||||
- [ ] #equipment
|
- [ ] #equipment
|
||||||
- [ ] [[spray beam]]
|
- [x] [[spray beam]]
|
||||||
- [x] Spray nozzle asset
|
- [x] Spray nozzle asset
|
||||||
- [x] Point spray
|
- [x] Point spray
|
||||||
- [x] Wide-angle spray
|
- [x] Wide-angle spray
|
||||||
- [x] Tall-angle spray?
|
- [x] Tall-angle spray?
|
||||||
- [ ] #maybe Spray-can
|
- [ ] #maybe Spray-can
|
||||||
- [x] [[toothbrush]]
|
- [x] [[toothbrush]]
|
||||||
- [ ] [[radar]]
|
- [ ] #maybe [[radar]]
|
||||||
- [ ] [[mp3 player]]
|
- [x] [[mp3 player]]
|
||||||
- [ ] [[manual]]
|
- [ ] [[manual]]
|
||||||
|
- [x] stickers
|
||||||
|
- [ ] NOTE redo sticker mechanics to use shader layer, not decals
|
||||||
- [ ] [[roomba]]
|
- [ ] [[roomba]]
|
||||||
- [ ] #mechanics
|
- [ ] #mechanics
|
||||||
- [x] [[grunk alert]]
|
- [x] [[grunk alert]]
|
||||||
@ -40,12 +42,20 @@
|
|||||||
- [x] [[medbay]]
|
- [x] [[medbay]]
|
||||||
- [x] [[ops center]]
|
- [x] [[ops center]]
|
||||||
- [ ] [[cargo bay]]
|
- [ ] [[cargo bay]]
|
||||||
|
- [ ] puzzle design
|
||||||
|
- [x] airlock?
|
||||||
|
- [ ] mess hall
|
||||||
|
- [ ] crew quarters
|
||||||
|
- [x] medbay
|
||||||
|
- [ ] ops center
|
||||||
|
- [ ] cargo bay
|
||||||
- [ ] [[story]]
|
- [ ] [[story]]
|
||||||
- [ ] ***ASSETS***
|
- [ ] ***ASSETS***
|
||||||
- [ ] HUD tools:
|
- [ ] HUD tools:
|
||||||
- [x] [[spray beam]]
|
- [x] [[spray beam]]
|
||||||
- [x] [[toothbrush]]
|
- [x] [[toothbrush]]
|
||||||
- [ ] [[mp3 player]]
|
- [x] [[mp3 player]]
|
||||||
|
- [x] stickers
|
||||||
- [ ] [[manual]]
|
- [ ] [[manual]]
|
||||||
- [ ] [[radar]]
|
- [ ] [[radar]]
|
||||||
- [ ] [[roomba]]
|
- [ ] [[roomba]]
|
||||||
@ -98,6 +108,9 @@
|
|||||||
- [ ] #maybe ops ambiance
|
- [ ] #maybe ops ambiance
|
||||||
- [ ] #maybe cargo bay ambiance
|
- [ ] #maybe cargo bay ambiance
|
||||||
- [ ] #maybe grunk node ambiance
|
- [ ] #maybe grunk node ambiance
|
||||||
|
- [ ] sticker sticking
|
||||||
|
- [ ] tool switch noise
|
||||||
|
- [ ] mp3 player ui noises
|
||||||
- [ ] models:
|
- [ ] models:
|
||||||
- [ ] [[grunk]] nodes:
|
- [ ] [[grunk]] nodes:
|
||||||
- [x] [[alarm]]
|
- [x] [[alarm]]
|
||||||
@ -117,6 +130,7 @@
|
|||||||
- [x] tall crate
|
- [x] tall crate
|
||||||
- [ ] other scatter
|
- [ ] other scatter
|
||||||
- [ ] external station model
|
- [ ] external station model
|
||||||
|
- [ ] audio cassette
|
||||||
- [ ] [[player ship]] props:
|
- [ ] [[player ship]] props:
|
||||||
- [ ] ship
|
- [ ] ship
|
||||||
- [ ] bunk
|
- [ ] bunk
|
||||||
|
Loading…
x
Reference in New Issue
Block a user