2344 lines
72 KiB
GDScript
2344 lines
72 KiB
GDScript
extends Actor
|
|
|
|
enum STATES{DEFAULT, BUSY, OBTAIN, EMOTING, FREECAM, FISHING_CHARGE, FISHING_CAST, FISHING, FISHING_CANCEL, FISHING_STRUGGLE, SHOVEL_CAST, SHOVEL_STRUGGLE, SHOVEL_CANCEL, \
|
|
NET_CAST, NET_STRUGGLE, NET_CANCEL, SHOWCASE, CONSUME_ITEM, METAL_DETECTOR, GUITAR, GAMBLING}
|
|
|
|
const GRAVITY = 32.0
|
|
const BAIT_DATA = {
|
|
"": {"catch": 0.0, "max_tier": 0, "quality": []},
|
|
|
|
"worms": {"catch": 0.06, "max_tier": 1, "quality": [1.0]},
|
|
"cricket": {"catch": 0.06, "max_tier": 2, "quality": [1.0, 0.05]},
|
|
"leech": {"catch": 0.06, "max_tier": 2, "quality": [1.0, 0.15, 0.05]},
|
|
"minnow": {"catch": 0.06, "max_tier": 2, "quality": [1.0, 0.5, 0.25, 0.05]},
|
|
"squid": {"catch": 0.06, "max_tier": 2, "quality": [1.0, 0.8, 0.45, 0.15, 0.05]},
|
|
"nautilus": {"catch": 0.06, "max_tier": 2, "quality": [1.0, 0.98, 0.75, 0.55, 0.25, 0.05]},
|
|
}
|
|
const PARTICLE_DATA = {
|
|
"dust_run": preload("res://Scenes/Particles/dust_running.tscn"),
|
|
"dust_land": preload("res://Scenes/Particles/dust_land.tscn"),
|
|
"splash": preload("res://Scenes/Particles/water_splash.tscn"),
|
|
"small_splash": preload("res://Scenes/Particles/small_splash.tscn"),
|
|
"music": preload("res://Scenes/Particles/music_particle.tscn"),
|
|
"kiss": preload("res://Scenes/Particles/kiss.tscn"),
|
|
}
|
|
|
|
export (NodePath) var hand_sprite_node
|
|
export (NodePath) var hand_bone_node
|
|
export var NPC_body = false
|
|
export var NPC_cosmetics = {"species": "species_cat", "pattern": "pattern_none", "primary_color": "pcolor_white", "secondary_color": "scolor_tan", "hat": "hat_none", "undershirt": "shirt_none", "overshirt": "overshirt_none", "title": "title_rank_1", "bobber": "bobber_default", "eye": "eye_halfclosed", "nose": "nose_cat", "mouth": "mouth_default", "accessory": [], "tail": "tail_cat"}
|
|
export var NPC_name = "NPC Test"
|
|
export var NPC_title = "npc title here"
|
|
|
|
var camera_zoom = 5.0
|
|
|
|
var direction = Vector3()
|
|
var gravity_vec = Vector3()
|
|
var dive_vec = Vector3()
|
|
var velocity = Vector3()
|
|
var player_scale = 1.0
|
|
var player_scale_y = 1.0
|
|
|
|
var cam_orbit_node = null
|
|
var cam_follow_node = null
|
|
var cam_push = 0.0
|
|
var cam_push_cur = 0.0
|
|
var cam_return = 1.0
|
|
var force_cam_look = false
|
|
var mouse_world_pos = Vector3()
|
|
var mouse_look = false
|
|
|
|
var state = STATES.DEFAULT
|
|
var walk_speed = 3.2
|
|
var slow_walk_speed = 1.0
|
|
var sprint_speed = 6.44
|
|
var sneak_speed = 1.3
|
|
var jump_height = 6.0
|
|
var jump_leap = 0.0
|
|
var dive_distance = 9.0
|
|
var accel = 64.0
|
|
var sprinting = false
|
|
var slow_walking = false
|
|
var sneaking = false
|
|
var diving = false
|
|
var request_jump = false
|
|
var ignore_snap = 0
|
|
var snapped = false
|
|
var sitting = false
|
|
var locked = false
|
|
var busy = false
|
|
var in_air = false
|
|
var gravity_disable = false
|
|
var hud
|
|
var int_text = ""
|
|
var interact_cooldown = 60
|
|
var xp_buildup = 0
|
|
var showcase_ref
|
|
|
|
var held_item = PlayerData.FALLBACK_ITEM
|
|
var caught_item = PlayerData.FALLBACK_ITEM
|
|
var held_item_weight = 1.0
|
|
var previous_item = 0
|
|
var primary_hold_timer = 0
|
|
var fish_zone_data = {}
|
|
var rod_cast_data = ""
|
|
var casted_bait = ""
|
|
var rod_cast_dist = 0.0
|
|
var rod_depth = 0
|
|
var failed_casts = 0
|
|
var recent_reel = 0.0
|
|
var item_scene = null
|
|
var bobber_hpos = Vector3()
|
|
var bobber_vpos = 0
|
|
var bobber_control = true
|
|
var last_valid_pos = Vector3()
|
|
var retract_splash = false
|
|
var show_local = false
|
|
var bait_warn = 2
|
|
var in_rain = false
|
|
var consume_on_state_change = - 1
|
|
var item_cooldown = 0
|
|
|
|
var rod_damage = 1.0
|
|
var rod_spd = 1.0
|
|
var rod_chance = 0.0
|
|
|
|
|
|
|
|
var boost_timer = 0
|
|
var boost_amt = 1.3
|
|
var boost_mult = 1.0
|
|
var catch_drink_timer = 0
|
|
var catch_drink_boost = 1.0
|
|
var catch_drink_reel = 1.0
|
|
var catch_drink_xp = 1.0
|
|
var catch_drink_gold_add = Vector2(0, 0)
|
|
var catch_drink_gold_percent = 0.0
|
|
var catch_drink_tier = 0
|
|
var drunk_timer = 0
|
|
var drunk_tier = 0
|
|
var drunk_wander_length = 0
|
|
var drunk_wander_dir = 0
|
|
|
|
var death_counter = 0
|
|
var metal_detect_flop = false
|
|
var metal_detect_alert_level = 0
|
|
var metal_detect_alert_cd = 0
|
|
|
|
var emoting = false
|
|
var emote_full = false
|
|
var emote_locked = false
|
|
var emote_looping = false
|
|
var animation_timer = 0
|
|
var animation_goal = 99
|
|
var buffer_state = - 1
|
|
var animation_data = {
|
|
"moving": false,
|
|
"sprinting": false,
|
|
"sneaking": false,
|
|
"emoting": false,
|
|
"emote_full": false,
|
|
"diving": false,
|
|
"sitting": false,
|
|
"alert": false,
|
|
"emote": "",
|
|
"arm_state": "",
|
|
"caught_item": {},
|
|
"arm_value": 0.0,
|
|
"item_bend": 0.0,
|
|
"busy": false,
|
|
"land": 0.0,
|
|
"talking": 0.0,
|
|
"recent_reel": 0.0,
|
|
"bobber_position": Vector3(),
|
|
"bobber_visible": false,
|
|
"caught_fish": false,
|
|
"player_scale": 1.0,
|
|
"player_scale_y": 1.0,
|
|
"mushroom": false,
|
|
"run_mult": 1.0,
|
|
"walk_mult": 1.25,
|
|
"drunk_tier": 0,
|
|
"wagging": false,
|
|
"emote_timescale": 1.0,
|
|
"back_bend": 0.0,
|
|
"dive_scrape": false,
|
|
"reel_slow": false,
|
|
"reel_fast": false,
|
|
"state": state,
|
|
}
|
|
|
|
|
|
|
|
var custom_held_item = ""
|
|
|
|
var cosmetic_data = {}
|
|
var selected_build_object
|
|
var old_rot = Vector3()
|
|
var rot_diff = 0.0
|
|
|
|
var prop_ids = []
|
|
var cam_move = false
|
|
var freecamming = false
|
|
|
|
onready var cam_base = $cam_base
|
|
onready var cam_pivot = $cam_base / cam_pivot
|
|
onready var camera = $Camera
|
|
onready var camera_point = $cam_base / cam_pivot / SpringArm / camera_point
|
|
onready var cam_arm = $cam_base / cam_pivot / SpringArm
|
|
onready var body = $body
|
|
onready var body_mesh = $body / player_body / Armature / Skeleton / body_main
|
|
onready var rot_help = $rot_help
|
|
onready var interact_range = $interact_range
|
|
onready var anim_tree = $body / AnimationTree
|
|
onready var skeleton = $body / player_body / Armature / Skeleton
|
|
onready var title = $Viewport / player_label
|
|
onready var item_sprite = get_node(hand_sprite_node)
|
|
onready var hand_bone = get_node(hand_bone_node)
|
|
onready var sound_emit = $sound_emit
|
|
onready var face = $body / player_body / Armature / Skeleton / face / player_face
|
|
onready var tail = $body / player_body / Armature / Skeleton / tail / holder / tail
|
|
onready var freecam_anchor = $camera_freecam_anchor
|
|
onready var sound_manager = $sound_manager
|
|
|
|
onready var fish_detect = $detection_zones / fishing_detect
|
|
onready var fishing_update = $detection_zones / fishing_update
|
|
onready var fishing_area = $detection_zones / fishing_detect / fishing_area
|
|
onready var fish_timer = $fish_catch_timer
|
|
onready var bobber_preview = $bobber_preview
|
|
onready var bobber = $bobber
|
|
onready var bobber_mesh = $bobber / bobber_mesh
|
|
onready var bobber_line = $bobber / line
|
|
onready var ripples = $bobber / ripples
|
|
onready var caught_fish = $bobber / caught_item
|
|
|
|
onready var shovel_area = $detection_zones / shovel_detect
|
|
onready var net_area = $detection_zones / net_detect
|
|
|
|
onready var safe_check = $safe_check
|
|
|
|
onready var lvlparticle = $emotion_particles / lvl_particles
|
|
onready var lvlparticleb = $emotion_particles / lvl_particles2
|
|
|
|
signal _animation_finished
|
|
signal _primary_release
|
|
signal _state_change
|
|
signal _menu_closed
|
|
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
add_to_group("player")
|
|
rot_help.set_as_toplevel(true)
|
|
cam_base.set_as_toplevel(true)
|
|
camera.set_as_toplevel(true)
|
|
freecam_anchor.set_as_toplevel(true)
|
|
anim_tree.tree_root = anim_tree.tree_root.duplicate(true)
|
|
_update_cosmetics(cosmetic_data)
|
|
title.visible = not dead_actor
|
|
|
|
if NPC_body:
|
|
camera.queue_free()
|
|
remove_from_group("player")
|
|
|
|
yield (get_tree(), "idle_frame")
|
|
var new = NPC_cosmetics
|
|
Network._send_actor_action(actor_id, "_update_cosmetics", [new])
|
|
_update_cosmetics(new)
|
|
|
|
yield (get_tree(), "idle_frame")
|
|
title.visible = true
|
|
title.label = NPC_name
|
|
title.title = NPC_title
|
|
|
|
|
|
func _setup_controlled():
|
|
if NPC_body: return
|
|
|
|
add_to_group("controlled_player")
|
|
camera = $Camera
|
|
camera.current = true
|
|
hud = load("res://Scenes/HUD/playerhud.tscn").instance()
|
|
hud.player = self
|
|
hud.connect("_player_sit", self, "_toggle_sit")
|
|
hud.connect("_play_emote", self, "_play_emote")
|
|
hud.connect("_menu_entered", self, "_hud_menu_entered")
|
|
hud.connect("_message_sent", self, "_message_sent")
|
|
hud.connect("_freecam_toggle", self, "_toggle_freecam")
|
|
get_tree().get_root().add_child(hud)
|
|
|
|
PlayerData.connect("_clear_all_props", self, "_clear_all_props")
|
|
PlayerData.connect("_place_prop", self, "_create_prop")
|
|
PlayerData.connect("_play_sfx", self, "_play_sfx")
|
|
PlayerData.connect("_play_guitar", self, "_strum_guitar")
|
|
PlayerData.connect("_hammer_guitar", self, "_hammer_string")
|
|
PlayerData.connect("_return_to_spawn", self, "_return_to_spawn")
|
|
PlayerData.connect("_punched", self, "_punched")
|
|
PlayerData.connect("_item_removal", self, "_item_removal")
|
|
var delayed_update = get_tree().create_timer(1.0).connect("timeout", self, "_change_cosmetics")
|
|
|
|
PlayerData.connect("_wag_toggle", self, "_wag")
|
|
PlayerData.connect("_kiss", self, "_kiss")
|
|
Network.connect("_user_connected", self, "_refresh_cosmetics")
|
|
|
|
|
|
func _setup_not_controlled():
|
|
camera = $Camera
|
|
camera.queue_free()
|
|
|
|
$bobber_preview.visible = false
|
|
$local_range.visible = false
|
|
$detection_zones / metal_detect_consume.monitoring = false
|
|
$detection_zones / metal_detect_consume.monitorable = false
|
|
|
|
|
|
$detection_zones / prop_detect.monitoring = false
|
|
$detection_zones / metal_detect_far.monitoring = false
|
|
$detection_zones / metal_detect.monitoring = false
|
|
$detection_zones / metal_detect_close.monitoring = false
|
|
$detection_zones / metal_detect_veryclose.monitoring = false
|
|
$detection_zones / punch.monitoring = false
|
|
$interact_range.monitoring = false
|
|
$water_detect.monitoring = false
|
|
$raincloud_check.monitoring = false
|
|
|
|
|
|
|
|
|
|
|
|
func _physics_process(delta):
|
|
_process_animation()
|
|
_process_sounds()
|
|
|
|
if ( not in_zone != $CollisionShape.disabled):
|
|
$CollisionShape.disabled = not in_zone
|
|
|
|
func _process(delta):
|
|
if controlled: $paint_node._paint_process(delta)
|
|
|
|
func _controlled_process(delta):
|
|
_get_input()
|
|
_process_movement(delta)
|
|
_process_timers()
|
|
_interact_check()
|
|
_update_animation_data()
|
|
_camera_update()
|
|
|
|
_freecam_input(delta)
|
|
|
|
body.visible = camera_zoom > 0.5 or cam_orbit_node != null
|
|
current_zone = world.active_zone
|
|
current_zone_owner = world.active_zone_owner
|
|
|
|
fish_detect.translation.z = - rod_cast_dist
|
|
bobber_preview.translation.z = - clamp(primary_hold_timer * 0.06, 1.5, 9.0)
|
|
if bobber_preview.is_colliding(): $"%bobber_prev_mesh".global_transform.origin = bobber_preview.get_collision_point() + Vector3(0, 0.05, 0)
|
|
bobber_preview.visible = state == STATES.FISHING_CHARGE
|
|
|
|
if recent_reel > 0: recent_reel -= 1
|
|
if interact_cooldown > 0: interact_cooldown -= 1
|
|
|
|
animation_data["reel_slow"] = recent_reel > 8
|
|
animation_data["reel_fast"] = state == STATES.FISHING_STRUGGLE
|
|
|
|
|
|
if (packet_send_interval == - 1 or Engine.get_physics_frames() % packet_send_interval == 0):
|
|
Network._send_actor_animation_update(actor_id, animation_data)
|
|
|
|
Network.MESSAGE_ORIGIN = global_transform.origin
|
|
$local_range.visible = show_local
|
|
|
|
$paint_node.global_transform.origin = mouse_world_pos
|
|
$metaldetect_dot.modulate.a = lerp($metaldetect_dot.modulate.a, 0.0, 0.1)
|
|
|
|
|
|
func _camera_update():
|
|
cam_push_cur = lerp(cam_push_cur, cam_push * rod_cast_dist, 0.2)
|
|
var push = global_transform.basis.z * cam_push_cur
|
|
camera_zoom = clamp(camera_zoom, 0.0, 20.0)
|
|
|
|
var cam_zoom = camera_zoom
|
|
var cam_zoom_lerp = 0.4
|
|
var cam_follow_point = true
|
|
var cam_follow_pos = Vector3()
|
|
var cam_follow_rot = Vector3()
|
|
var sit_add = Vector3(0, - 0.2, 0.0) if sitting else Vector3.ZERO
|
|
var cam_base_pos = global_transform.origin + push + sit_add
|
|
|
|
var desired_fov = 50
|
|
if sprinting and direction != Vector3.ZERO:
|
|
desired_fov += 2
|
|
if boost_timer > 0: desired_fov += 2 * boost_amt
|
|
if animation_data["mushroom"]: desired_fov += 10
|
|
|
|
camera.fov = lerp(camera.fov, desired_fov, 0.2)
|
|
|
|
if is_instance_valid(cam_orbit_node) and cam_orbit_node.is_visible_in_tree():
|
|
cam_base_pos = cam_orbit_node.global_transform.origin
|
|
|
|
if is_instance_valid(cam_follow_node) and cam_follow_node.is_visible_in_tree():
|
|
cam_follow_point = false
|
|
cam_follow_pos = cam_follow_node.global_transform.origin
|
|
cam_follow_rot = cam_follow_node.global_rotation
|
|
|
|
var cam_speed = 0.08
|
|
if cam_follow_point:
|
|
cam_return = lerp(cam_return, 1.0, cam_speed * 0.5)
|
|
camera.global_transform.origin = lerp(camera.global_transform.origin, camera_point.global_transform.origin, cam_return)
|
|
camera.rotation.x = lerp_angle(camera.rotation.x, camera_point.global_rotation.x, cam_return)
|
|
camera.rotation.y = lerp_angle(camera.rotation.y, camera_point.global_rotation.y, cam_return)
|
|
camera.rotation.z = lerp_angle(camera.rotation.z, camera_point.global_rotation.z, cam_return)
|
|
else :
|
|
cam_return = 0.0
|
|
camera.global_transform.origin = lerp(camera.global_transform.origin, cam_follow_pos, cam_speed)
|
|
camera.rotation.x = lerp_angle(camera.rotation.x, cam_follow_rot.x, cam_speed)
|
|
camera.rotation.y = lerp_angle(camera.rotation.y, cam_follow_rot.y, cam_speed)
|
|
camera.rotation.z = lerp_angle(camera.rotation.z, cam_follow_rot.z, cam_speed)
|
|
|
|
cam_base.global_transform.origin = cam_base_pos
|
|
cam_arm.spring_length = lerp(cam_arm.spring_length, cam_zoom, cam_zoom_lerp)
|
|
|
|
func _interact_check():
|
|
if not controlled: return
|
|
var in_range = false
|
|
for area in interact_range.get_overlapping_areas():
|
|
if area.is_in_group("interactable") and area.is_visible_in_tree():
|
|
int_text = area.text
|
|
in_range = true
|
|
break
|
|
if hud:
|
|
hud.interact = in_range
|
|
hud.int_text = int_text
|
|
|
|
func _hud_menu_entered(menu):
|
|
if menu == 0:
|
|
if not freecamming:
|
|
cam_orbit_node = null
|
|
cam_follow_node = null
|
|
force_cam_look = false
|
|
_exit_showcase()
|
|
emit_signal("_menu_closed")
|
|
|
|
func _process_timers():
|
|
if catch_drink_timer > 0:
|
|
catch_drink_timer -= 1
|
|
if catch_drink_timer <= 0:
|
|
catch_drink_boost = 1.0
|
|
catch_drink_reel = 1.0
|
|
catch_drink_xp = 1.0
|
|
catch_drink_gold_add = Vector2(0, 0)
|
|
catch_drink_gold_percent = 0.0
|
|
|
|
drunk_tier = 0
|
|
if drunk_timer > 0:
|
|
drunk_timer -= 1
|
|
if drunk_timer >= 19000: drunk_tier = 3
|
|
elif drunk_timer >= 10000: drunk_tier = 2
|
|
elif drunk_timer > 0: drunk_tier = 1
|
|
else : drunk_tier = 0
|
|
|
|
if item_cooldown > 0: item_cooldown -= 1
|
|
|
|
|
|
|
|
|
|
|
|
func _get_input():
|
|
direction = Vector3.ZERO
|
|
|
|
if Input.is_action_just_released("primary_action"): _primary_action_release()
|
|
if Input.is_action_pressed("primary_action"): _primary_action_hold()
|
|
else : primary_hold_timer = 0
|
|
|
|
if busy:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
return
|
|
|
|
if Input.is_action_pressed("secondary_action") or camera_zoom <= 0.0:
|
|
if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED:
|
|
PlayerData.original_mouse_position = get_tree().get_nodes_in_group("world_viewport")[0].get_mouse_position()
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
else :
|
|
if Input.mouse_mode != Input.MOUSE_MODE_VISIBLE:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
Input.warp_mouse_position(PlayerData.original_mouse_position)
|
|
|
|
if Input.is_action_just_released("zoom_in"): camera_zoom -= 0.5
|
|
if Input.is_action_just_released("zoom_out"): camera_zoom += 0.5
|
|
|
|
if Input.is_action_just_pressed("interact"): _interact()
|
|
|
|
if Input.is_action_just_pressed("bind_1"): _equip_hotbar(0)
|
|
if Input.is_action_just_pressed("bind_2"): _equip_hotbar(1)
|
|
if Input.is_action_just_pressed("bind_3"): _equip_hotbar(2)
|
|
if Input.is_action_just_pressed("bind_4"): _equip_hotbar(3)
|
|
if Input.is_action_just_pressed("bind_5"): _equip_hotbar(4)
|
|
|
|
if Input.is_action_just_pressed("bark"):
|
|
_bark()
|
|
if Input.is_action_just_pressed("kiss"):
|
|
_kiss()
|
|
|
|
if locked: return
|
|
|
|
|
|
if is_instance_valid(camera):
|
|
var camera_cam = camera
|
|
var ray_length = 1000
|
|
var mouse_pos = get_tree().get_nodes_in_group("world_viewport")[0].get_mouse_position() / Globals.pixelize_amount
|
|
var from = camera_cam.project_ray_origin(mouse_pos)
|
|
var to = from + camera_cam.project_ray_normal(mouse_pos) * ray_length
|
|
var space_state = get_world().get_direct_space_state()
|
|
var result = space_state.intersect_ray(from, to, [])
|
|
if result.has("position"):
|
|
mouse_world_pos = result["position"]
|
|
mouse_world_pos.y = global_transform.origin.y
|
|
|
|
if freecamming: return
|
|
if Input.is_action_just_pressed("move_jump"): request_jump = true
|
|
|
|
mouse_look = false
|
|
|
|
if sitting: return
|
|
|
|
if Input.is_action_pressed("move_forward"): direction -= cam_base.transform.basis.z
|
|
if Input.is_action_pressed("move_back"): direction += cam_base.transform.basis.z
|
|
if Input.is_action_pressed("move_right"): direction += cam_base.transform.basis.x
|
|
if Input.is_action_pressed("move_left"): direction -= cam_base.transform.basis.x
|
|
|
|
if drunk_wander_length > 0:
|
|
direction += drunk_wander_dir
|
|
drunk_wander_length -= 1
|
|
|
|
mouse_look = Input.is_action_pressed("mouse_look")
|
|
|
|
sprinting = not Input.is_action_pressed("move_sneak") and Input.is_action_pressed("move_sprint")
|
|
sneaking = Input.is_action_pressed("move_sneak") and not Input.is_action_pressed("move_sprint")
|
|
slow_walking = Input.is_action_pressed("move_walk")
|
|
|
|
if emote_locked:
|
|
request_jump = false
|
|
direction = Vector3.ZERO
|
|
|
|
func _input(event):
|
|
if not controlled: return
|
|
|
|
var mouse_sens = OptionsMenu.mouse_sens
|
|
var invert = Vector2(1, 1)
|
|
if OptionsMenu.mouse_invert == 1: invert.x = - 1
|
|
elif OptionsMenu.mouse_invert == 2: invert.y = - 1
|
|
elif OptionsMenu.mouse_invert == 3: invert = Vector2( - 1, - 1)
|
|
|
|
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
|
cam_base.rotation_degrees.y -= event.relative.x * mouse_sens * invert.x
|
|
cam_pivot.rotation_degrees.x -= event.relative.y * mouse_sens * invert.y
|
|
cam_pivot.rotation_degrees.x = clamp(cam_pivot.rotation_degrees.x, - 80, 80)
|
|
|
|
func _unhandled_input(event):
|
|
if not controlled: return
|
|
|
|
if event.is_action_pressed("primary_action"): _primary_action()
|
|
|
|
|
|
|
|
|
|
func _process_movement(delta):
|
|
var snap_vec = Vector3(0, - 0.4, 0)
|
|
var y_slow = 0.02
|
|
|
|
if is_on_floor() and in_air:
|
|
if gravity_vec.y <= - 12.0 and not diving:
|
|
diving = true
|
|
dive_vec = gravity_vec.length() * - transform.basis.z * 0.2
|
|
player_scale_y = 1.0 - clamp(((abs(gravity_vec.y) / 24.0) * 6.0), 0.0, 0.6)
|
|
in_air = false
|
|
_sync_particle("dust_land", Vector3(0, - 1, 0))
|
|
_sync_sfx("land")
|
|
animation_data["land"] = 0.3
|
|
elif gravity_vec.y < - 6.0:
|
|
in_air = true
|
|
|
|
player_scale_y = lerp(player_scale_y, 1.0, 0.35)
|
|
|
|
if is_on_floor() and ignore_snap <= 0:
|
|
y_slow = 0.2
|
|
gravity_vec = get_floor_normal() * - 1.0
|
|
snapped = true
|
|
elif snapped and ignore_snap <= 0:
|
|
gravity_vec = Vector3.ZERO
|
|
snapped = false
|
|
else :
|
|
snap_vec = Vector3.ZERO
|
|
var grav = GRAVITY * Vector3.DOWN * delta
|
|
gravity_vec += grav
|
|
|
|
if request_jump:
|
|
request_jump = false
|
|
snap_vec = Vector3.ZERO
|
|
if is_on_floor():
|
|
_sync_sfx("jump")
|
|
snapped = false
|
|
diving = false
|
|
gravity_vec = Vector3(0, jump_height, 0)
|
|
if sprinting and jump_leap > 0.0:
|
|
gravity_vec += - transform.basis.z.normalized() * jump_leap
|
|
elif not diving:
|
|
_sync_sfx("dive_woosh")
|
|
snapped = false
|
|
diving = true
|
|
dive_vec = - transform.basis.z.normalized() * dive_distance
|
|
dive_vec.y = 0
|
|
gravity_vec += Vector3(0, jump_height * 0.5, 0)
|
|
_toggle_sit(true)
|
|
|
|
if ignore_snap > 0:
|
|
snap_vec = Vector3.ZERO
|
|
ignore_snap -= 1
|
|
snapped = false
|
|
|
|
boost_mult = 1.0
|
|
if boost_timer > 0:
|
|
boost_timer -= 1
|
|
boost_mult = boost_amt
|
|
|
|
var _speed = walk_speed
|
|
if sprinting: _speed = sprint_speed * boost_mult
|
|
elif sneaking: _speed = sneak_speed
|
|
elif slow_walking: _speed = slow_walk_speed
|
|
var _accel = accel if is_on_floor() else accel * 0.35
|
|
|
|
var speed_mult = 1.0
|
|
|
|
|
|
speed_mult = clamp(speed_mult - ((held_item_weight / 25.0) * 0.05), 0.15, 1.0)
|
|
|
|
if diving: speed_mult = 0.0
|
|
if gravity_disable: gravity_vec = Vector3.ZERO
|
|
|
|
velocity = velocity.move_toward(direction.normalized() * _speed * speed_mult, delta * _accel)
|
|
move_and_slide_with_snap(velocity + gravity_vec + dive_vec, snap_vec, Vector3.UP)
|
|
|
|
dive_vec = dive_vec.move_toward(Vector3.ZERO, delta * _accel * y_slow)
|
|
if not diving: dive_vec = Vector3.ZERO
|
|
|
|
rot_help.global_transform.origin = global_transform.origin
|
|
|
|
if direction != Vector3.ZERO:
|
|
var dir = direction
|
|
if diving and dive_vec != Vector3.ZERO: dir = dive_vec.normalized()
|
|
|
|
rot_help.look_at(cam_base.global_transform.origin + dir, Vector3.UP)
|
|
rotation.y = lerp_angle(rotation.y, rot_help.rotation.y, 0.2)
|
|
elif force_cam_look:
|
|
rot_help.look_at(camera.global_transform.origin, Vector3.UP)
|
|
rotation.y = lerp_angle(rotation.y, rot_help.rotation.y, 0.2)
|
|
elif mouse_look and not busy:
|
|
rot_help.look_at(mouse_world_pos, Vector3.UP)
|
|
rot_diff = abs(rot_help.rotation.y - rotation.y)
|
|
rotation.y = lerp_angle(rotation.y, rot_help.rotation.y, 0.2)
|
|
|
|
rot_diff = lerp(rot_diff, 0.0, 0.5)
|
|
|
|
if diving and dive_vec.length() > 0.4 and is_on_floor():
|
|
|
|
animation_data["dive_scrape"] = true
|
|
|
|
if Engine.get_idle_frames() % 4 == 0:
|
|
_sync_particle("dust_run", Vector3(0, - 0.8, 0))
|
|
else :
|
|
|
|
animation_data["dive_scrape"] = false
|
|
|
|
if gravity_vec.y < - 250:
|
|
_kill()
|
|
|
|
|
|
|
|
|
|
func _enter_state(new_state):
|
|
if new_state == - 1: return
|
|
|
|
if consume_on_state_change != - 1:
|
|
PlayerData._remove_item(consume_on_state_change, false)
|
|
consume_on_state_change = - 1
|
|
|
|
state = new_state
|
|
emit_signal("_state_change")
|
|
cam_push = 0.0
|
|
animation_data["bobber_visible"] = false
|
|
|
|
match state:
|
|
STATES.DEFAULT:
|
|
animation_data["item_bend"] = 0.0
|
|
locked = false
|
|
STATES.BUSY: locked = false
|
|
STATES.OBTAIN: locked = true
|
|
STATES.SHOWCASE:
|
|
locked = true
|
|
_equip_item(PlayerData._find_item_code(showcase_ref), true, true)
|
|
|
|
STATES.FISHING:
|
|
cam_push = - 0.3
|
|
locked = true
|
|
animation_data["bobber_visible"] = true
|
|
PlayerData.emit_signal("_help_update", "hold to reel (SPRINT reels quicker)")
|
|
_enter_animation("rod_idle", true)
|
|
STATES.FISHING_CANCEL:
|
|
animation_data["item_bend"] = 0.1
|
|
cam_push = - 0.3
|
|
locked = true
|
|
rod_cast_dist = 0.0
|
|
animation_data["bobber_visible"] = true
|
|
PlayerData.emit_signal("_item_equip", held_item.ref)
|
|
_bobber_retract()
|
|
_enter_animation("rod_retract", false, true, STATES.DEFAULT)
|
|
STATES.FISHING_CAST:
|
|
cam_push = - 0.3
|
|
animation_data["bobber_visible"] = true
|
|
locked = true
|
|
STATES.FISHING_CHARGE:
|
|
cam_push = 0.0
|
|
locked = false
|
|
STATES.FISHING_STRUGGLE:
|
|
animation_data["item_bend"] = - 0.7
|
|
cam_push = - 0.3
|
|
animation_data["bobber_visible"] = true
|
|
locked = true
|
|
_enter_animation("rod_struggle", true)
|
|
|
|
STATES.GUITAR: locked = true
|
|
|
|
STATES.SHOVEL_CAST: locked = true
|
|
STATES.SHOVEL_STRUGGLE:
|
|
locked = true
|
|
_shovel_check()
|
|
STATES.SHOVEL_CANCEL:
|
|
locked = true
|
|
_enter_animation("shovel_retract", false, true, STATES.DEFAULT)
|
|
|
|
STATES.NET_CAST: locked = true
|
|
STATES.NET_STRUGGLE:
|
|
locked = true
|
|
_net_check()
|
|
STATES.NET_CANCEL:
|
|
locked = true
|
|
_enter_animation("net_retract", false, true, STATES.DEFAULT)
|
|
|
|
STATES.CONSUME_ITEM:
|
|
locked = false
|
|
_equip_item({"ref": 0}, true, true)
|
|
_enter_state(STATES.DEFAULT)
|
|
|
|
func _primary_action():
|
|
match state:
|
|
STATES.DEFAULT:
|
|
_use_item()
|
|
STATES.OBTAIN:
|
|
_enter_animation("equip", false, true, 0, false, 1.5)
|
|
|
|
func _primary_action_hold():
|
|
primary_hold_timer += 1
|
|
|
|
match state:
|
|
STATES.DEFAULT:
|
|
return
|
|
STATES.FISHING:
|
|
_enter_animation("rod_reel", true)
|
|
rod_cast_dist -= 0.04 if Input.is_action_pressed("move_sprint") else 0.01
|
|
bobber_control = true
|
|
recent_reel = 15
|
|
if rod_cast_dist < 1.5: _enter_state(STATES.FISHING_CANCEL)
|
|
|
|
func _primary_action_release():
|
|
emit_signal("_primary_release")
|
|
|
|
match state:
|
|
STATES.DEFAULT:
|
|
_release_item()
|
|
STATES.FISHING:
|
|
_enter_animation("rod_idle", true)
|
|
STATES.METAL_DETECTOR:
|
|
_enter_state(STATES.DEFAULT)
|
|
|
|
|
|
|
|
|
|
|
|
func _interact():
|
|
if not controlled or interact_cooldown > 0: return
|
|
for area in interact_range.get_overlapping_areas():
|
|
if area.is_in_group("interactable") and area.is_visible_in_tree():
|
|
area._activate(self)
|
|
interact_cooldown = 60
|
|
return
|
|
|
|
func _enter_zone(zone, entrance_id, zone_owner = - 1):
|
|
if not controlled: return
|
|
world._enter_zone(zone, zone_owner)
|
|
PlayerData.player_saved_zone = zone
|
|
PlayerData.player_saved_zone_owner = zone_owner
|
|
|
|
print("Finding entrance w id: ", entrance_id, " and owner: ", zone_owner)
|
|
for entrance in get_tree().get_nodes_in_group("area_entrance"):
|
|
print(entrance.entrance_id, ": ", entrance.entrance_owner, " ?")
|
|
if entrance.entrance_id == entrance_id and entrance.entrance_owner == zone_owner:
|
|
global_transform.origin = entrance.global_transform.origin
|
|
last_valid_pos = global_transform.origin
|
|
return
|
|
|
|
print("Fallback!")
|
|
global_transform.origin = world.map.spawn_position.global_transform.origin
|
|
world._enter_zone("main_zone", - 1)
|
|
PlayerData.player_saved_zone = "main_zone"
|
|
PlayerData.player_saved_zone_owner = - 1
|
|
last_valid_pos = global_transform.origin
|
|
|
|
func _obtain_item(ref, bonus_text = [], journal_check = true):
|
|
old_rot = rotation
|
|
showcase_ref = ref
|
|
_equip_item({"ref": - 1}, true, true)
|
|
_enter_animation("equip", false, false, STATES.SHOWCASE, false, 1.5)
|
|
_play_sfx("strum")
|
|
|
|
|
|
var data = PlayerData._find_item_code(ref)
|
|
var text = "You caught a " + PlayerData._get_item_name(ref) + "! [color=#d5aa73](It's " + str(data["size"]) + "cm!)[/color]\n\n" + str(Globals.item_data[data["id"]]["file"].catch_blurb)
|
|
|
|
if journal_check:
|
|
var new = true
|
|
for type in PlayerData.journal_logs.keys():
|
|
for entry in PlayerData.journal_logs[type].keys():
|
|
if entry == data.id and PlayerData.journal_logs[type][entry].count > 1:
|
|
new = false
|
|
break
|
|
if new:
|
|
text = "Woah, a new creature! " + text
|
|
|
|
hud.dialogue_text = [text]
|
|
if bonus_text != []: hud.dialogue_text.append_array(bonus_text)
|
|
hud._change_menu(6)
|
|
|
|
force_cam_look = true
|
|
yield (get_tree().create_timer(0.1), "timeout")
|
|
cam_follow_node = $catch_cam_position
|
|
|
|
func _level_up():
|
|
yield (get_tree().create_timer(0.4), "timeout")
|
|
var bubble = title._create_level_bubble()
|
|
Network._send_actor_action(actor_id, "_sync_level_bubble", [], false)
|
|
GlobalAudio._play_sound("jingle_win")
|
|
|
|
_play_emote("emote_cheer", "happy")
|
|
|
|
$emotion_particles / lvl_particles.restart()
|
|
$emotion_particles / lvl_particles2.restart()
|
|
|
|
func _exit_showcase():
|
|
if state != STATES.SHOWCASE: return
|
|
_exit_animation()
|
|
_enter_state(STATES.DEFAULT)
|
|
_equip_item(PlayerData._find_item_code(previous_item), false)
|
|
get_tree().create_tween().tween_property(self, "rotation", old_rot, 0.3)
|
|
|
|
if xp_buildup > 0:
|
|
PlayerData._add_xp(ceil(xp_buildup))
|
|
xp_buildup = 0
|
|
|
|
func _equip_hotbar(slot):
|
|
if locked or not PlayerData.hotbar.keys().has(slot): return
|
|
var ref = PlayerData.hotbar[slot]
|
|
_equip_item(PlayerData._find_item_code(ref))
|
|
|
|
func _equip_item(item_data, skip_anim = false, forced = false, set_prev = true):
|
|
if set_prev and held_item["ref"] != 0: previous_item = held_item["ref"]
|
|
if (state != STATES.DEFAULT and not forced) or held_item["ref"] == item_data["ref"]: return
|
|
|
|
if not item_data.keys().has("id") or not Globals.item_data.keys().has(item_data["id"]):
|
|
item_data = PlayerData.FALLBACK_ITEM
|
|
|
|
PlayerData.emit_signal("_item_equip", item_data["ref"])
|
|
|
|
if not skip_anim:
|
|
_sync_sfx("equip")
|
|
_enter_state(STATES.BUSY)
|
|
_enter_animation("equip", false, false, STATES.DEFAULT, false, 1.5)
|
|
yield (self, "_animation_finished")
|
|
|
|
|
|
var held_data = item_data.duplicate()
|
|
|
|
hud.show_bait = Globals.item_data[item_data["id"]]["file"].show_bait
|
|
|
|
var data = Globals.item_data[item_data["id"]]["file"]
|
|
held_item_weight = item_data["size"]
|
|
if not data.uses_size: held_item_weight = 0.0
|
|
|
|
_update_held_item(held_data)
|
|
Network._send_actor_action(actor_id, "_update_held_item", [held_item], false)
|
|
|
|
func _use_item():
|
|
if held_item.empty(): return
|
|
var item_data = Globals.item_data[held_item["id"]]["file"]
|
|
if has_method(item_data.action) and item_data.action != "":
|
|
callv(item_data.action, item_data.action_params)
|
|
|
|
func _release_item():
|
|
if held_item.empty(): return
|
|
var item_data = Globals.item_data[held_item["id"]]["file"]
|
|
if has_method(item_data.release_action) and item_data.release_action != "":
|
|
call(item_data.release_action)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _cast_fishing_rod():
|
|
rod_cast_data = PlayerData.LURE_DATA[PlayerData.lure_selected].effect_id
|
|
animation_data["caught_item"] = {}
|
|
bait_warn = 1
|
|
|
|
rod_damage = [1, 3, 10, 20, 35, 50][PlayerData.rod_power_level]
|
|
rod_spd = [0.0, 0.1, 0.24, 0.4, 0.7, 1.0][PlayerData.rod_speed_level]
|
|
rod_chance = [0.0, 0.02, 0.04, 0.06, 0.08, 0.1][PlayerData.rod_chance_level]
|
|
|
|
_enter_state(STATES.FISHING_CHARGE)
|
|
_enter_animation("rod_wind", true, false, - 1, false)
|
|
yield (self, "_primary_release")
|
|
if state != STATES.FISHING_CHARGE: return
|
|
_enter_state(STATES.FISHING_CAST)
|
|
_sync_sfx("woosh", null, 1.0, 0.4)
|
|
var strength = clamp(primary_hold_timer * 0.06, 1.5, 9.0)
|
|
rod_cast_dist = strength
|
|
fish_detect.translation.z = - strength
|
|
|
|
var is_valid_fishing_spot = false
|
|
if bobber_preview.is_colliding() and bobber_preview.get_collider().is_in_group("valid_water"):
|
|
is_valid_fishing_spot = true
|
|
|
|
_bobber_cast(rod_cast_dist, bobber_preview.get_collision_point() + Vector3(0, 0.75, 0), is_valid_fishing_spot)
|
|
|
|
rod_depth = 0
|
|
|
|
casted_bait = PlayerData.bait_selected
|
|
if casted_bait != "" and PlayerData.bait_inv[casted_bait] <= 0: casted_bait = ""
|
|
|
|
_exit_animation()
|
|
if is_valid_fishing_spot:
|
|
animation_data["item_bend"] = 0.3
|
|
retract_splash = true
|
|
_enter_animation("rod_cast", false, true, STATES.FISHING)
|
|
else :
|
|
animation_data["item_bend"] = 0.3
|
|
retract_splash = false
|
|
_enter_animation("rod_cast", false, true, STATES.FISHING_CANCEL)
|
|
|
|
yield (get_tree().create_timer(0.4), "timeout")
|
|
animation_data["item_bend"] = - 0.2
|
|
|
|
func _on_fish_catch_timer_timeout():
|
|
if not controlled: return
|
|
|
|
fish_timer.wait_time = rand_range(2.0, 3.0)
|
|
fish_timer.start()
|
|
|
|
if state != STATES.FISHING: return
|
|
var fish_type = "ocean"
|
|
var junk_mult = 1.0
|
|
|
|
|
|
fish_zone_data = {"id": - 1, "boost": 0.0}
|
|
for zone in fishing_area.get_overlapping_areas():
|
|
if zone.is_in_group("fish_zone"):
|
|
fish_zone_data["id"] = zone.id
|
|
fish_zone_data["boost"] = zone.chance_boost
|
|
junk_mult = zone.junk_mult
|
|
if zone.fish_type != "": fish_type = zone.fish_type
|
|
|
|
var fish_chance = 0.0
|
|
var base_chance = BAIT_DATA[casted_bait]["catch"]
|
|
fish_chance = base_chance
|
|
fish_chance += (base_chance * failed_casts)
|
|
fish_chance += (base_chance * rod_chance)
|
|
fish_chance += fish_zone_data["boost"] * fish_chance
|
|
if recent_reel > 0: fish_chance *= 1.1
|
|
if rod_cast_data == "attractive": fish_chance *= 1.3
|
|
if in_rain: fish_chance *= 1.1
|
|
|
|
fish_chance *= catch_drink_boost
|
|
print("Fish chance w ", fish_chance, "w type ", fish_type)
|
|
|
|
bait_warn -= 1
|
|
if bait_warn <= 0 and fish_chance <= 0.0:
|
|
bait_warn = 8
|
|
var text = ""
|
|
if casted_bait == "":
|
|
text = "[color=#ac0029]You've got no bait attached! You won't catch any fish like that...[/color]"
|
|
else :
|
|
text = "[color=#ac0029]Seems nothing is going to bite... perhaps your bait isn't for this water...[/color]"
|
|
|
|
Network._update_chat(text)
|
|
|
|
if randf() > fish_chance:
|
|
failed_casts += 0.05
|
|
return
|
|
failed_casts = 0.0
|
|
|
|
|
|
var bait_use_chance = 1.0
|
|
if rod_cast_data == "efficient": bait_use_chance = 0.8
|
|
|
|
if randf() < bait_use_chance: PlayerData._use_bait(casted_bait)
|
|
else : PlayerData._send_notification("The Efficient Lure saved your bait!")
|
|
var max_tier = BAIT_DATA[casted_bait]["max_tier"]
|
|
|
|
var double_bait = 0.0
|
|
if ["large", "sparkling", "double"].has(rod_cast_data): double_bait = 0.25
|
|
if randf() < double_bait:
|
|
PlayerData._use_bait(casted_bait)
|
|
PlayerData._send_notification("Your lure used extra bait...", 1)
|
|
|
|
if rod_cast_data == "gold":
|
|
for i in 2: PlayerData._use_bait(casted_bait)
|
|
PlayerData._send_notification("Your golden lure used extra bait...", 1)
|
|
|
|
var treasure_mult = 1.0
|
|
if rod_cast_data == "magnet": treasure_mult = 2.0
|
|
if rod_cast_data == "salty": fish_type = "ocean"
|
|
if rod_cast_data == "fresh": fish_type = "lake"
|
|
|
|
var force_av_size = false
|
|
|
|
if randf() < 0.05 * treasure_mult * junk_mult:
|
|
fish_type = "water_trash"
|
|
max_tier = 0
|
|
force_av_size = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if in_rain and randf() < 0.08:
|
|
fish_type = "rain"
|
|
|
|
|
|
var rolls = []
|
|
for i in 3:
|
|
var roll = Globals._roll_loot_table(fish_type, max_tier)
|
|
var s = Globals._roll_item_size(roll)
|
|
rolls.append([roll, s])
|
|
|
|
|
|
var reroll_type = "none"
|
|
if rod_cast_data == "small": reroll_type = "small"
|
|
if rod_cast_data == "sparkling": reroll_type = "tier"
|
|
if rod_cast_data == "large": reroll_type = "large"
|
|
if rod_cast_data == "gold": reroll_type = "rare"
|
|
|
|
var chosen = rolls[0]
|
|
for roll in rolls:
|
|
match reroll_type:
|
|
"none":
|
|
chosen = roll
|
|
|
|
"small":
|
|
if roll[1] < chosen[1]:
|
|
chosen = roll
|
|
|
|
"large":
|
|
if roll[1] > chosen[1]:
|
|
chosen = roll
|
|
|
|
"tier":
|
|
var old_tier = Globals.item_data[chosen[0]]["file"].tier
|
|
var new_tier = Globals.item_data[roll[0]]["file"].tier
|
|
if new_tier > old_tier:
|
|
chosen = roll
|
|
|
|
"rare":
|
|
var new_rare = Globals.item_data[roll[0]]["file"].rare
|
|
if new_rare:
|
|
chosen = roll
|
|
|
|
var fish_roll = chosen[0]
|
|
var size = chosen[1]
|
|
|
|
|
|
var quality = PlayerData.ITEM_QUALITIES.NORMAL
|
|
var r = randf()
|
|
for q in PlayerData.ITEM_QUALITIES.size():
|
|
if BAIT_DATA[casted_bait]["quality"].size() - 1 < q:
|
|
print("bait does not support rarity ", q)
|
|
break
|
|
if randf() < BAIT_DATA[casted_bait]["quality"][q]:
|
|
quality = q
|
|
print("-------------------------Rolled Quality: ", quality)
|
|
|
|
if randf() < 0.02 * treasure_mult:
|
|
fish_roll = "treasure_chest"
|
|
size = 60.0
|
|
quality = 0
|
|
|
|
var data = Globals.item_data[fish_roll]["file"]
|
|
var quality_data = PlayerData.QUALITY_DATA[quality]
|
|
|
|
if force_av_size: size = data.average_size
|
|
|
|
var diff_mult = clamp(size / data.average_size, 0.7, 1.8)
|
|
var difficulty = clamp((data.catch_difficulty * diff_mult * quality_data.diff) + quality_data.bdiff, 1.0, 250.0)
|
|
|
|
var xp_mult = size / data.average_size
|
|
if xp_mult < 0.15: xp_mult = 1.25 + xp_mult
|
|
xp_mult = max(0.5, xp_mult)
|
|
var xp_add = ceil(data.obtain_xp * xp_mult * catch_drink_xp * quality_data.worth)
|
|
|
|
print("Total Rolls: ", rolls)
|
|
print("Roll fish ", fish_roll, " with size ", size, " and diff Mult: ", diff_mult)
|
|
|
|
if fish_zone_data["id"] != - 1:
|
|
_wipe_actor(fish_zone_data["id"])
|
|
Network._send_actor_action(actor_id, "_wipe_actor", [fish_zone_data["id"]])
|
|
|
|
_enter_state(STATES.FISHING_STRUGGLE)
|
|
animation_data["alert"] = true
|
|
yield (get_tree().create_timer(1.0), "timeout")
|
|
|
|
animation_data["alert"] = false
|
|
|
|
var delay_time = 0
|
|
while hud.using_chat:
|
|
yield (get_tree().create_timer(0.15), "timeout")
|
|
delay_time += 1
|
|
|
|
if delay_time > 200:
|
|
_enter_state(STATES.FISHING_CANCEL)
|
|
return
|
|
|
|
hud._open_minigame("fishing3", {"fish": fish_roll, "rod_type": rod_cast_data, "reel_mult": catch_drink_reel, "quality": quality, "damage": rod_damage, "speed": rod_spd}, difficulty)
|
|
var success = yield (hud, "_minigame_finished")
|
|
print("SUCCESS: ", success)
|
|
if success:
|
|
animation_data["caught_item"] = {"id": fish_roll, "size": size}
|
|
_enter_state(STATES.FISHING_CANCEL)
|
|
yield (self, "_state_change")
|
|
|
|
var ref
|
|
var catches = 1
|
|
var bonus_text = []
|
|
|
|
if rod_cast_data == "double" and randf() < 0.15:
|
|
catches = 2
|
|
bonus_text.append("Your Double Hook doubled the fish!")
|
|
|
|
if PlayerData.rod_luck_level > 0 and randf() < 0.15:
|
|
bonus_text.append("How lucky! You found a bonus [color=#d57900]Coin Bag[/color] aswell!")
|
|
PlayerData._add_item("luck_moneybag", - 1, randi() % 15 + 15, PlayerData.rod_luck_level)
|
|
|
|
var tags = []
|
|
|
|
for i in catches:
|
|
ref = PlayerData._add_item(fish_roll, - 1, size, quality, tags)
|
|
PlayerData._log_item(fish_roll, size, quality)
|
|
PlayerData._quest_progress("catch", fish_roll)
|
|
PlayerData._quest_progress("catch_type", data.loot_table)
|
|
PlayerData._quest_progress("catch_small", PlayerData._get_size_type(fish_roll, size))
|
|
PlayerData._quest_progress("catch_big", PlayerData._get_size_type(fish_roll, size))
|
|
if fish_roll == "treasure_chest": PlayerData._quest_progress("catch_treasure")
|
|
if in_rain: PlayerData._quest_progress("catch_rain")
|
|
if data.tier == 2: PlayerData._quest_progress("catch_hightier")
|
|
xp_buildup += xp_add
|
|
|
|
PlayerData._catch_fish()
|
|
|
|
_obtain_item(ref, bonus_text)
|
|
|
|
if rod_cast_data == "lucky":
|
|
var worth = PlayerData._get_item_worth(ref)
|
|
var gold = max(1, ceil(worth * rand_range(0.01, 0.1)))
|
|
PlayerData.money += gold
|
|
PlayerData._send_notification("Your Lucky Lure got you $" + str(gold) + "!")
|
|
|
|
if catch_drink_gold_add != Vector2(0, 0):
|
|
var gold = max(1, ceil(rand_range(catch_drink_gold_add.x, catch_drink_gold_add.y)))
|
|
PlayerData.money += gold
|
|
PlayerData._send_notification("Your Catcher's Luck got you $" + str(gold) + "!")
|
|
|
|
if catch_drink_gold_percent > 0.0:
|
|
var worth = PlayerData._get_item_worth(ref)
|
|
var gold = max(1, ceil(rand_range(worth * 0.01, worth * catch_drink_gold_percent)))
|
|
PlayerData.money += gold
|
|
PlayerData._send_notification("Your Catcher's Luck Ultra got you $" + str(gold) + "!")
|
|
|
|
|
|
else :
|
|
_enter_state(STATES.FISHING_CANCEL)
|
|
|
|
func _wipe_actor(id):
|
|
var actor = world._get_actor_by_id(id)
|
|
print("Wiping actor ", id, " : ", actor)
|
|
if is_instance_valid(actor):
|
|
actor._deinstantiate(true)
|
|
|
|
|
|
func _shovel():
|
|
_enter_state(STATES.SHOVEL_CAST)
|
|
_enter_animation("shovel_dig", false, true, STATES.SHOVEL_STRUGGLE)
|
|
|
|
func _shovel_check():
|
|
var mound = false
|
|
|
|
var area
|
|
for a in shovel_area.get_overlapping_areas():
|
|
if a.is_in_group("mound"):
|
|
mound = true
|
|
area = a
|
|
|
|
if is_instance_valid(area):
|
|
var id = area.owner.actor_id
|
|
_wipe_actor(id)
|
|
Network._send_actor_action(actor_id, "_wipe_actor", [id])
|
|
|
|
if mound:
|
|
_enter_animation("shovel_struggle", true, true)
|
|
hud._open_minigame("shoveling", {"damage": 5.0})
|
|
var success = yield (hud, "_minigame_finished")
|
|
print("SUCCESS: ", success)
|
|
if success:
|
|
_enter_state(STATES.SHOVEL_CANCEL)
|
|
yield (self, "_state_change")
|
|
var ref = PlayerData._add_item("spider")
|
|
|
|
|
|
_obtain_item(ref)
|
|
else :
|
|
_enter_state(STATES.SHOVEL_CANCEL)
|
|
else :
|
|
_enter_state(STATES.SHOVEL_CANCEL)
|
|
|
|
|
|
func _cast_net():
|
|
_enter_state(STATES.NET_CAST)
|
|
_enter_animation("net_use", false, true, STATES.NET_STRUGGLE)
|
|
|
|
func _net_check():
|
|
var bug = false
|
|
|
|
var area
|
|
for a in net_area.get_overlapping_areas():
|
|
if a.is_in_group("bug"):
|
|
bug = true
|
|
area = a
|
|
|
|
var bug_id = ""
|
|
if is_instance_valid(area):
|
|
var id = area.owner.actor_id
|
|
bug_id = area.owner.bug_id
|
|
_wipe_actor(id)
|
|
Network._send_actor_action(actor_id, "_wipe_actor", [id])
|
|
|
|
if bug:
|
|
_enter_animation("net_struggle", true, true)
|
|
hud._open_minigame("shoveling", {"damage": 5.0})
|
|
var success = yield (hud, "_minigame_finished")
|
|
print("SUCCESS: ", success)
|
|
if success:
|
|
_enter_state(STATES.NET_CANCEL)
|
|
yield (self, "_state_change")
|
|
var size = Globals._roll_item_size(bug_id)
|
|
var ref = PlayerData._add_item(bug_id, - 1, size)
|
|
|
|
|
|
_obtain_item(ref)
|
|
else :
|
|
_enter_state(STATES.NET_CANCEL)
|
|
else :
|
|
_enter_state(STATES.NET_CANCEL)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _toggle_freecam():
|
|
if busy: return
|
|
|
|
if not freecamming:
|
|
PlayerData._send_notification("entering freecam mode")
|
|
freecamming = true
|
|
hud.freecamming = true
|
|
cam_orbit_node = freecam_anchor
|
|
freecam_anchor.global_transform.origin = global_transform.origin
|
|
else :
|
|
PlayerData._send_notification("exiting freecam mode")
|
|
freecamming = false
|
|
hud.freecamming = false
|
|
cam_orbit_node = null
|
|
|
|
func _freecam_input(delta):
|
|
if not freecamming: return
|
|
|
|
var speed = 4.0
|
|
if Input.is_action_pressed("move_sprint"):
|
|
speed = 7.0
|
|
if Input.is_action_pressed("move_sneak"):
|
|
speed = 1.0
|
|
var max_dist = 15.0
|
|
var build_dir = Vector3.ZERO
|
|
|
|
if Input.is_action_pressed("move_forward"): build_dir -= cam_base.transform.basis.z
|
|
if Input.is_action_pressed("move_back"): build_dir += cam_base.transform.basis.z
|
|
if Input.is_action_pressed("move_right"): build_dir += cam_base.transform.basis.x
|
|
if Input.is_action_pressed("move_left"): build_dir -= cam_base.transform.basis.x
|
|
if Input.is_action_pressed("move_up"): build_dir += cam_base.transform.basis.y
|
|
if Input.is_action_pressed("move_down"): build_dir -= cam_base.transform.basis.y
|
|
|
|
freecam_anchor.global_transform.origin += build_dir * speed * delta
|
|
|
|
freecam_anchor.global_transform.origin.x = clamp(freecam_anchor.global_transform.origin.x, global_transform.origin.x - max_dist, global_transform.origin.x + max_dist)
|
|
freecam_anchor.global_transform.origin.y = clamp(freecam_anchor.global_transform.origin.y, global_transform.origin.y - max_dist, global_transform.origin.y + max_dist)
|
|
freecam_anchor.global_transform.origin.z = clamp(freecam_anchor.global_transform.origin.z, global_transform.origin.z - max_dist, global_transform.origin.z + max_dist)
|
|
|
|
|
|
|
|
|
|
|
|
func _create_prop(ref, offset = Vector3(0, 1, 0)):
|
|
if not controlled: return
|
|
|
|
|
|
for prop in prop_ids:
|
|
if prop.ref == ref:
|
|
_wipe_actor(prop.id)
|
|
prop_ids.erase(prop)
|
|
PlayerData._send_notification("clearing prop", 1)
|
|
PlayerData.props_placed = prop_ids
|
|
PlayerData.emit_signal("_prop_update")
|
|
return
|
|
|
|
|
|
if $detection_zones / prop_detect.get_overlapping_bodies().size() > 0 or not is_on_floor() or not $detection_zones / prop_ray.is_colliding():
|
|
PlayerData._send_notification("invalid prop placement", 1)
|
|
return
|
|
|
|
|
|
if prop_ids.size() > 4:
|
|
PlayerData._send_notification("prop limit reached", 1)
|
|
return
|
|
|
|
|
|
var item = PlayerData._find_item_code(ref)
|
|
var data = Globals.item_data[item["id"]]["file"]
|
|
var ver_offset = Vector3(0, 1.0, 0) * (1.0 - player_scale)
|
|
print(ver_offset)
|
|
var pos = global_transform.origin + (global_transform.basis.z * - 2.0) - offset + ver_offset
|
|
var rot = rotation + Vector3(0, deg2rad(180), 0)
|
|
var prop_code = data.prop_code
|
|
|
|
|
|
var blacklist = ["island_tiny", "island_med", "island_big"]
|
|
if current_zone_owner != - 1:
|
|
if blacklist.has(prop_code):
|
|
PlayerData._send_notification("this prop cannot be spawned here...", 1)
|
|
return
|
|
|
|
|
|
var new_id = Network._sync_create_actor(prop_code, pos, current_zone, - 1, Network.STEAM_ID, {"rotation": rot, "current_zone_owner": current_zone_owner})
|
|
prop_ids.append({"id": new_id, "ref": ref, "prop_id": data.action})
|
|
PlayerData.props_placed = prop_ids
|
|
PlayerData.emit_signal("_prop_update")
|
|
PlayerData._send_notification("prop placed", 0)
|
|
|
|
_sync_particle("dust_land", pos, true)
|
|
_sync_sfx("poof", pos)
|
|
|
|
func _clear_props():
|
|
if prop_ids.size() <= 0:
|
|
PlayerData._send_notification("no props to undo", 1)
|
|
return
|
|
PlayerData._send_notification("undo prop", 0)
|
|
_wipe_actor(prop_ids[prop_ids.size() - 1][0])
|
|
prop_ids.remove(prop_ids.size() - 1)
|
|
|
|
func _clear_all_props():
|
|
if prop_ids.size() <= 0:
|
|
PlayerData._send_notification("no props to clear", 1)
|
|
return
|
|
|
|
PlayerData._send_notification("clearing all props", 0)
|
|
for prop in prop_ids:
|
|
_wipe_actor(prop.id)
|
|
prop_ids.clear()
|
|
PlayerData.props_placed = prop_ids
|
|
PlayerData.emit_signal("_prop_update")
|
|
|
|
func _item_place_prop():
|
|
if not controlled: return
|
|
_create_prop(held_item.ref)
|
|
|
|
|
|
|
|
|
|
|
|
func _update_animation_data():
|
|
if animation_data["emote"] != "":
|
|
var anim = $body / player_body / AnimationPlayer.get_animation(animation_data["emote"])
|
|
animation_timer += 1
|
|
animation_goal = floor((anim.length * 60) / animation_data["emote_timescale"])
|
|
if animation_timer >= animation_goal and emoting and animation_goal > 0 and not emote_looping:
|
|
print("Finished Emoting ", animation_data["emote"], " bufferstate: ", buffer_state)
|
|
emit_signal("_animation_finished")
|
|
emoting = false
|
|
emote_full = false
|
|
emote_locked = false
|
|
animation_data["emote"] = ""
|
|
if buffer_state != - 1: _enter_state(buffer_state)
|
|
|
|
animation_data["emoting"] = emoting
|
|
animation_data["emote_full"] = emoting and emote_full
|
|
animation_data["moving"] = direction != Vector3.ZERO or rot_diff > 0.05
|
|
animation_data["sprinting"] = sprinting and direction != Vector3.ZERO
|
|
animation_data["sneaking"] = sneaking and direction != Vector3.ZERO
|
|
animation_data["diving"] = diving
|
|
animation_data["sitting"] = sitting
|
|
animation_data["busy"] = busy and state == STATES.DEFAULT and not emoting
|
|
animation_data["land"] = lerp(animation_data["land"], 0.0, 0.04)
|
|
animation_data["talking"] = lerp(animation_data["talking"], 0.0, 0.1)
|
|
animation_data["recent_reel"] = lerp(animation_data["recent_reel"], recent_reel, 0.2)
|
|
animation_data["caught_fish"] = state == STATES.FISHING_STRUGGLE
|
|
animation_data["player_scale"] = lerp(animation_data["player_scale"], player_scale, 0.06)
|
|
animation_data["player_scale_y"] = lerp(animation_data["player_scale_y"], player_scale_y, 0.06)
|
|
animation_data["run_mult"] = 1.15 * boost_mult
|
|
animation_data["walk_mult"] = 1.25 if not slow_walking else 0.7
|
|
animation_data["drunk_tier"] = drunk_tier
|
|
animation_data["state"] = state
|
|
|
|
$emotion_particles / mushroom_trail.emitting = animation_data["mushroom"]
|
|
$emotion_particles / drunk_particles.emitting = animation_data["drunk_tier"] > 1
|
|
if is_on_floor(): animation_data["mushroom"] = false
|
|
|
|
if not bobber_control:
|
|
animation_data["bobber_position"] = Vector3(bobber_hpos.x, bobber_vpos, bobber_hpos.z)
|
|
else :
|
|
var pos = global_transform.origin + ( - rod_cast_dist * global_transform.basis.z)
|
|
pos.y = bobber_vpos + sin(OS.get_ticks_msec() * 0.002) * 0.05
|
|
animation_data["bobber_position"] = lerp(animation_data["bobber_position"], pos, 0.2)
|
|
|
|
func _process_animation():
|
|
var anim_lerp = 0.4
|
|
|
|
var emote_type = 0
|
|
if animation_data["emoting"]: emote_type = 1
|
|
if animation_data["emote_full"]: emote_type = 2
|
|
|
|
anim_tree.set("parameters/emote_full/blend_amount", lerp(anim_tree.get("parameters/emote_full/blend_amount"), float(emote_type == 2), anim_lerp))
|
|
if anim_tree.get("parameters/emote_full/blend_amount") < 0.1 and emote_type != 2: anim_tree.set("parameters/emote_full/blend_amount", 0.0)
|
|
anim_tree.set("parameters/emote_half/blend_amount", lerp(anim_tree.get("parameters/emote_half/blend_amount"), float(emote_type == 1), anim_lerp))
|
|
if anim_tree.get("parameters/emote_half/blend_amount") < 0.1 and emote_type != 1: anim_tree.set("parameters/emote_half/blend_amount", 0.0)
|
|
|
|
anim_tree.set("parameters/arms/blend_amount", lerp(anim_tree.get("parameters/arms/blend_amount"), float( not animation_data["emoting"]), anim_lerp))
|
|
anim_tree.set("parameters/movement/blend_amount", lerp(anim_tree.get("parameters/movement/blend_amount"), float(animation_data["moving"]), anim_lerp))
|
|
anim_tree.set("parameters/run_blend/blend_amount", lerp(anim_tree.get("parameters/run_blend/blend_amount"), float(animation_data["sprinting"]) - float(animation_data["sneaking"]), anim_lerp))
|
|
anim_tree.set("parameters/dive/blend_amount", lerp(anim_tree.get("parameters/dive/blend_amount"), float(animation_data["diving"]), anim_lerp))
|
|
anim_tree.set("parameters/arm_blend/blend_position", float(animation_data["arm_value"]))
|
|
anim_tree.set("parameters/sitting/blend_amount", lerp(anim_tree.get("parameters/sitting/blend_amount"), float(animation_data["sitting"]), anim_lerp))
|
|
anim_tree.set("parameters/thinking/blend_amount", lerp(anim_tree.get("parameters/thinking/blend_amount"), float(animation_data["busy"]), anim_lerp))
|
|
anim_tree.set("parameters/land/blend_amount", lerp(anim_tree.get("parameters/land/blend_amount"), float(animation_data["land"]), anim_lerp))
|
|
anim_tree.set("parameters/talking/blend_amount", lerp(anim_tree.get("parameters/talking/blend_amount"), float(animation_data["talking"]), anim_lerp))
|
|
anim_tree.set("parameters/runmodif/scale", animation_data["run_mult"])
|
|
anim_tree.set("parameters/walkmodif/scale", animation_data["walk_mult"])
|
|
anim_tree.set("parameters/emote_time/scale", animation_data["emote_timescale"])
|
|
anim_tree.set("parameters/emote_timeb/scale", animation_data["emote_timescale"])
|
|
|
|
face._show_blush(animation_data["drunk_tier"] > 1)
|
|
if animation_data["caught_item"] != caught_item:
|
|
caught_item = animation_data["caught_item"]
|
|
_update_caught_item(animation_data["caught_item"])
|
|
|
|
if item_scene:
|
|
item_scene.item_bend = lerp(item_scene.item_bend, animation_data["item_bend"], 0.4)
|
|
bobber_line.end_anchor = item_scene.get_node(item_scene.hotspot_node).global_transform.origin
|
|
bobber_line.y_drop = - 1.5 + ((animation_data["recent_reel"] / 15.0) * 0.5)
|
|
if animation_data["caught_fish"]: bobber_line.y_drop = 0
|
|
if bobber.visible: bobber.global_transform.origin = animation_data["bobber_position"] + Vector3(0, (0.0 if not animation_data["caught_fish"] else - 0.3), 0)
|
|
bobber.visible = animation_data["bobber_visible"]
|
|
bobber_line.active = bobber.visible
|
|
|
|
|
|
if animation_data["player_scale"] != scale.y:
|
|
scale = animation_data["player_scale"] * Vector3.ONE
|
|
scale.y *= animation_data["player_scale_y"]
|
|
|
|
bobber_line.line_scale = animation_data["player_scale"]
|
|
|
|
ripples.visible = animation_data["state"] == STATES.FISHING
|
|
var rip_anim = "default" if animation_data["recent_reel"] <= 1.0 else "wake"
|
|
if ripples.animation != rip_anim: ripples.animation = rip_anim
|
|
|
|
var root = anim_tree.tree_root
|
|
var node = root.get_node("emote_anim")
|
|
var node_b = root.get_node("emote_anim_b")
|
|
if node.animation != animation_data["emote"]:
|
|
anim_tree.set("parameters/emote_sync/seek_position", 0.0)
|
|
anim_tree.set("parameters/emote_half_sync/seek_position", 0.0)
|
|
node.set_animation(animation_data["emote"])
|
|
node_b.set_animation(animation_data["emote"])
|
|
|
|
$"%head_alert".visible = animation_data["alert"]
|
|
|
|
tail.sitting = animation_data["sitting"]
|
|
tail.diving = animation_data["diving"]
|
|
tail.motion = float(animation_data["moving"])
|
|
tail.wagging = animation_data["wagging"]
|
|
|
|
|
|
if animation_data["back_bend"] != 0.0:
|
|
var pose = skeleton.get_bone_pose(1)
|
|
pose = pose.rotated(Vector3(1, 0, 0), animation_data["back_bend"])
|
|
skeleton.set_bone_custom_pose(1, pose)
|
|
else :
|
|
skeleton.set_bone_custom_pose(1, Transform())
|
|
|
|
func _enter_animation(anim_name, loop = false, _locked = true, state_enter = - 1, full_anim = true, timescale = 1.0):
|
|
if anim_name == animation_data["emote"]: return
|
|
diving = false
|
|
|
|
animation_data["emote_timescale"] = timescale
|
|
|
|
|
|
emote_full = full_anim
|
|
emote_locked = _locked
|
|
emote_looping = loop
|
|
buffer_state = state_enter if not emote_looping else - 1
|
|
if emote_looping: _enter_state(state_enter)
|
|
animation_data["emote"] = anim_name
|
|
animation_timer = 0
|
|
emoting = true
|
|
|
|
func _exit_animation():
|
|
emit_signal("_animation_finished")
|
|
emoting = false
|
|
emote_full = false
|
|
emote_locked = false
|
|
emote_looping = false
|
|
animation_data["emote"] = ""
|
|
|
|
func _update_held_item(new):
|
|
if new.empty() or held_item == new: return
|
|
|
|
held_item = new
|
|
var item_data = Globals.item_data[new["id"]]["file"]
|
|
var alt_scale_mult = 1.0
|
|
|
|
|
|
item_sprite.texture = item_data.icon.duplicate() if (item_data.show_item and not item_data.show_scene) else null
|
|
|
|
|
|
|
|
if is_instance_valid(item_scene): item_scene.queue_free()
|
|
item_scene = null
|
|
if item_data.show_scene and item_data.item_scene:
|
|
item_scene = item_data.item_scene.instance()
|
|
hand_bone.add_child(item_scene)
|
|
|
|
var scale_mult = 0.07 - clamp(new["size"] * 0.01, 0.01, 0.061)
|
|
var item_scale = 1.0 if not item_data.uses_size else new["size"] * scale_mult
|
|
item_scale *= alt_scale_mult
|
|
item_sprite.scale = Vector3(item_scale, item_scale, item_scale)
|
|
|
|
|
|
var y = 0.0
|
|
var offs = 0.0
|
|
var back_bend = 0.0
|
|
if item_data.uses_size:
|
|
y = clamp(item_scale * item_scale * 0.08, 0.0, 0.36)
|
|
offs = clamp(item_scale * item_scale, 0.0, 16.0)
|
|
back_bend = clamp(item_scale * item_scale, 0.0, 55.0)
|
|
|
|
item_sprite.translation.y = y
|
|
item_sprite.offset.y = item_data.hold_offset + offs
|
|
|
|
|
|
$body / player_body / Armature / Skeleton / BoneAttachment / Spatial.rotation_degrees = Vector3(0.0, 0.0, back_bend * 0.7)
|
|
|
|
item_sprite.translation.z = 0.0
|
|
item_sprite.vel = 0.0
|
|
item_sprite.mult = clamp(item_scale * 3.5, 0.0, 1.2) if item_data.category == "fish" and item_data.alive else 0.0
|
|
|
|
item_sprite.modulate = Color("#ffffff")
|
|
item_sprite.opacity = 1.0
|
|
for child in item_sprite.get_children(): child.emitting = false
|
|
|
|
if PlayerData.QUALITY_DATA.has(new["quality"]):
|
|
item_sprite.modulate = Color(PlayerData.QUALITY_DATA[new["quality"]]["mod"])
|
|
item_sprite.opacity = PlayerData.QUALITY_DATA[new["quality"]]["op"]
|
|
if PlayerData.QUALITY_DATA[new["quality"]]["particle"] > - 1: item_sprite.get_child(PlayerData.QUALITY_DATA[new["quality"]]["particle"]).emitting = true
|
|
|
|
animation_data["arm_value"] = item_data.arm_value
|
|
animation_data["back_bend"] = deg2rad( - back_bend)
|
|
|
|
func _update_caught_item(new):
|
|
if new.empty():
|
|
caught_fish.texture = null
|
|
return
|
|
caught_item = new
|
|
|
|
var item_data = Globals.item_data[new["id"]]["file"]
|
|
caught_fish.texture = item_data.icon.duplicate() if item_data.show_item else null
|
|
|
|
var item_scale = 1.0 if not item_data.uses_size else new["size"] * 0.01
|
|
caught_fish.scale = Vector3(item_scale, item_scale, item_scale)
|
|
|
|
func _bobber_cast(dist, end, splash):
|
|
bobber_control = false
|
|
var height = dist * 0.4
|
|
height += max(0, global_transform.origin.y - end.y)
|
|
|
|
end.y -= 1
|
|
|
|
bobber_hpos = global_transform.origin
|
|
bobber_vpos = global_transform.origin.y
|
|
yield (get_tree().create_timer(0.4), "timeout")
|
|
|
|
var tween = get_tree().create_tween()
|
|
|
|
tween.set_trans(1)
|
|
tween.set_ease(1)
|
|
tween.tween_property(self, "bobber_vpos", end.y + height, dist * 0.05)
|
|
tween.set_ease(0)
|
|
tween.tween_property(self, "bobber_vpos", end.y - (height * 0.2), dist * 0.05)
|
|
if splash:
|
|
tween.tween_callback(self, "_bobber_splash")
|
|
|
|
|
|
tween.set_trans(1)
|
|
tween.set_ease(1)
|
|
tween.tween_property(self, "bobber_vpos", end.y + (height * 0.1), (dist * 0.05))
|
|
tween.set_ease(0)
|
|
tween.tween_property(self, "bobber_vpos", end.y - (height * 0.05), (dist * 0.1))
|
|
|
|
|
|
tween.set_trans(1)
|
|
tween.set_ease(1)
|
|
tween.tween_property(self, "bobber_vpos", end.y, (dist * 0.1))
|
|
|
|
var htween = get_tree().create_tween()
|
|
htween.set_trans(4)
|
|
htween.set_ease(1)
|
|
htween.tween_property(self, "bobber_hpos", end + (global_transform.basis.z * 0.5), dist * 0.1)
|
|
htween.tween_property(self, "bobber_hpos", end + (global_transform.basis.z * 0.2), dist * 0.15)
|
|
htween.tween_property(self, "bobber_hpos", end, dist * 0.1)
|
|
|
|
yield (htween, "finished")
|
|
bobber_control = true
|
|
|
|
func _bobber_retract():
|
|
bobber_control = false
|
|
bobber_hpos = bobber.global_transform.origin
|
|
bobber_vpos = bobber.global_transform.origin.y
|
|
|
|
yield (get_tree().create_timer(0.4), "timeout")
|
|
|
|
if retract_splash: _bobber_splash("splashb")
|
|
var tween = get_tree().create_tween()
|
|
tween.set_trans(1)
|
|
tween.set_ease(1)
|
|
tween.tween_property(self, "bobber_vpos", global_transform.origin.y + 2.0, 0.3)
|
|
tween.set_ease(0)
|
|
tween.tween_property(self, "bobber_vpos", global_transform.origin.y, 0.3)
|
|
|
|
var htween = get_tree().create_tween()
|
|
htween.tween_property(self, "bobber_hpos", global_transform.origin, 0.6)
|
|
|
|
func _bobber_splash(sfx = "splash"):
|
|
_sync_particle("splash", bobber.global_transform.origin, true)
|
|
_sync_sfx(sfx, Vector3(bobber_hpos.x, bobber_vpos, bobber_hpos.z))
|
|
|
|
|
|
|
|
|
|
|
|
func _toggle_sit(exit = false):
|
|
if not exit: sitting = not sitting
|
|
else : sitting = false
|
|
|
|
func _play_emote(emote_id, emotion = ""):
|
|
if emote_id == "": return
|
|
|
|
if emote_id == "sit":
|
|
_toggle_sit()
|
|
elif not emote_locked:
|
|
_enter_animation(emote_id, false, true)
|
|
if emotion != "":
|
|
_sync_face_emote(emotion)
|
|
|
|
|
|
|
|
|
|
|
|
func _change_cosmetics():
|
|
if cosmetic_data == PlayerData.cosmetics_equipped: return
|
|
var new = PlayerData.cosmetics_equipped.duplicate()
|
|
if not dead_actor: Network._send_actor_action(actor_id, "_update_cosmetics", [new])
|
|
_update_cosmetics(new)
|
|
|
|
func _update_cosmetics(data):
|
|
var valid = true
|
|
for key in PlayerData.FALLBACK_COSM.keys():
|
|
if not data.keys().has(key):
|
|
print("missing key ", key)
|
|
valid = false
|
|
for key in data.keys():
|
|
if not (data[key] is Array):
|
|
if not Globals._cosmetic_exists(data[key]):
|
|
print("cosm ", data[key], " does not exist")
|
|
valid = false
|
|
else :
|
|
for c in data[key]:
|
|
if not Globals._cosmetic_exists(c):
|
|
print("cosm ", data[key], " does not exist")
|
|
valid = false
|
|
|
|
if not valid: data = PlayerData.FALLBACK_COSM.duplicate()
|
|
|
|
cosmetic_data = data
|
|
|
|
for child in skeleton.get_children():
|
|
if child.is_in_group("cosmetic"): child.queue_free()
|
|
|
|
if data.empty(): return
|
|
|
|
title.label = str(Network._get_username_from_id(owner_id))
|
|
title.title = Globals.cosmetic_data[data["title"]]["file"].title
|
|
|
|
face._setup_face(data)
|
|
var species_id = Globals.cosmetic_data[data.species]["file"].cos_internal_id
|
|
var species = _create_cosmetic(data["species"], species_id)
|
|
_create_cosmetic(data["undershirt"], species_id)
|
|
_create_cosmetic(data["overshirt"], species_id)
|
|
_create_cosmetic(data["legs"], species_id)
|
|
_create_cosmetic(data["hat"], species_id)
|
|
for misc in data["accessory"]: _create_cosmetic(misc, species_id)
|
|
|
|
|
|
var pattern = Globals.cosmetic_data[data["pattern"]]["file"]
|
|
body_mesh.material_override.set_shader_param("texture_albedo", pattern.body_pattern[0])
|
|
|
|
var primary_color = Globals.cosmetic_data[data["primary_color"]]["file"]
|
|
var secondary_color = Globals.cosmetic_data[data["secondary_color"]]["file"] if pattern.body_pattern[0] else Globals.cosmetic_data[data["primary_color"]]["file"]
|
|
body_mesh.material_override.set_shader_param("albedo", primary_color.main_color)
|
|
body_mesh.material_override.set_shader_param("albedo_secondary", secondary_color.main_color)
|
|
|
|
|
|
var tail_data = Globals.cosmetic_data[data["tail"]]["file"]
|
|
tail._load_tail(tail_data.mesh, primary_color.main_color)
|
|
|
|
if species:
|
|
species.material_override.set_shader_param("albedo", primary_color.main_color)
|
|
species.material_override.set_shader_param("albedo_secondary", secondary_color.main_color)
|
|
|
|
match data["species"]:
|
|
"species_cat": species.material_override.set_shader_param("texture_albedo", pattern.body_pattern[1])
|
|
"species_dog": species.material_override.set_shader_param("texture_albedo", pattern.body_pattern[2])
|
|
|
|
if not data.keys().has("bobber") or data["bobber"] == "": data["bobber"] = "bobber_default"
|
|
var bobber_file = Globals.cosmetic_data[data["bobber"]]["file"]
|
|
bobber_mesh.mesh = bobber_file.mesh
|
|
bobber_mesh.set_surface_material(0, bobber_file.material)
|
|
if bobber_file.secondary_material: bobber_mesh.set_surface_material(1, bobber_file.secondary_material)
|
|
if bobber_file.third_material: bobber_mesh.set_surface_material(2, bobber_file.third_material)
|
|
|
|
func _create_cosmetic(id, species_id = 0):
|
|
if id == "": return
|
|
if not Globals.cosmetic_data.keys().has(id):
|
|
print("Failed finding cosmetic: ", id)
|
|
return
|
|
print("Creating Cosmetic: ", id)
|
|
var data = Globals.cosmetic_data[id]["file"]
|
|
|
|
if data.scene_replace:
|
|
var bone_attach = BoneAttachment.new()
|
|
skeleton.add_child(bone_attach)
|
|
bone_attach.bone_name = "pelvis"
|
|
bone_attach.add_to_group("cosmetic")
|
|
|
|
var cosm = data.scene_replace.instance()
|
|
bone_attach.add_child(cosm)
|
|
return cosm
|
|
|
|
var cosm = preload("res://Scenes/Entities/Player/cosmetic_node.tscn").instance()
|
|
cosm.mesh = data.mesh
|
|
if data.species_alt_mesh.size() > 0:
|
|
cosm.mesh = data.species_alt_mesh[species_id]
|
|
|
|
cosm.skin = data.mesh_skin
|
|
|
|
if not data.material:
|
|
cosm.material_override = preload("res://Assets/Shaders/player_skins.tres").duplicate()
|
|
cosm.material_override.set_shader_param("albedo", data.main_color)
|
|
cosm.material_override.set_shader_param("albedo_secondary", data.main_color)
|
|
cosm.material_override.set_shader_param("texture_albedo", null)
|
|
else :
|
|
|
|
cosm.material_override = null
|
|
cosm.set_surface_material(0, data.material)
|
|
if data.secondary_material: cosm.set_surface_material(1, data.secondary_material)
|
|
|
|
cosm.skeleton = skeleton.get_path()
|
|
skeleton.add_child(cosm)
|
|
return cosm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _on_step_timer_timeout():
|
|
if not controlled: return
|
|
|
|
|
|
if randf() < 0.03 * drunk_tier and drunk_wander_length <= 0:
|
|
drunk_wander_length = randi() % 25 + 5
|
|
drunk_wander_dir = Vector3(
|
|
rand_range( - 1, 1),
|
|
0.0,
|
|
rand_range( - 1, 1))
|
|
|
|
if state == STATES.FISHING_STRUGGLE:
|
|
_sync_particle("small_splash", bobber.global_transform.origin, true)
|
|
|
|
if recent_reel > 0 and state == STATES.FISHING:
|
|
fishing_update.translation.z = - rod_cast_dist
|
|
fishing_update.force_raycast_update()
|
|
if fishing_update.is_colliding() and not fishing_update.get_collider().is_in_group("valid_water"):
|
|
_enter_state(STATES.FISHING_CANCEL)
|
|
|
|
if velocity != Vector3.ZERO:
|
|
var vol = 1.6
|
|
if sprinting: vol = 2.8
|
|
elif sneaking: vol = 0.3
|
|
|
|
if is_on_floor() and sprinting: _sync_particle("dust_run", Vector3(0, - 0.95, 0))
|
|
|
|
if is_on_floor() and safe_check.is_colliding() and safe_check.get_collision_normal() == Vector3(0, 1, 0) and not gravity_disable:
|
|
if death_counter > 0: death_counter -= 1
|
|
last_valid_pos = global_transform.origin
|
|
|
|
PlayerData.player_saved_position = global_transform.origin
|
|
|
|
|
|
|
|
|
|
|
|
func _message_sent(text):
|
|
|
|
var split = text.split(" ")
|
|
for s in split:
|
|
match s:
|
|
":(", ":[", "D:", ";_;", ";~;", ":C", ":c": _sync_face_emote("sad")
|
|
":)", ":D", ":]": _sync_face_emote("love")
|
|
"xD", "!!!", "<3", "xd", "LMAO", "LOL": _sync_face_emote("happy")
|
|
">:(", "D:<", ">:[": _sync_face_emote("angry")
|
|
":/", ":|": _sync_face_emote("flat")
|
|
":3", ":3c", ">:3c", ">:3": _sync_face_emote("cat")
|
|
"O.o", "!?!?", "?!?!", ":o", ":O": _sync_face_emote("surprised")
|
|
|
|
var bubble = title._create_speech_bubble(text, PlayerData.voice_speed)
|
|
bubble.connect("_letter_said", self, "_sync_talk")
|
|
Network._send_actor_action(actor_id, "_sync_create_bubble", [text], false)
|
|
|
|
func _sync_talk(letter):
|
|
var blacklist = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
|
|
if not blacklist.has(letter.to_lower()): return
|
|
|
|
animation_data["talking"] = 0.4
|
|
_talk(letter, PlayerData.voice_pitch)
|
|
Network._send_actor_action(actor_id, "_talk", [letter, PlayerData.voice_pitch], false)
|
|
|
|
func _talk(letter, pitch = 1.5):
|
|
if not in_zone or not visible: return
|
|
|
|
face._talk()
|
|
sound_manager._construct_voice(letter, "NewVoice", pitch)
|
|
|
|
func _sync_face_emote(emotion):
|
|
_face_emote(emotion)
|
|
Network._send_actor_action(actor_id, "_face_emote", [emotion], false)
|
|
|
|
func _sync_create_bubble(text):
|
|
title._create_speech_bubble(text)
|
|
|
|
func _sync_level_bubble(text):
|
|
title._create_level_bubble(text)
|
|
$emotion_particles / lvl_particles.restart()
|
|
$emotion_particles / lvl_particles2.restart()
|
|
|
|
func _face_emote(emotion):
|
|
face._emote(emotion, 2.4)
|
|
|
|
|
|
|
|
|
|
|
|
func _sync_particle(id, offset = Vector3.ZERO, global = false):
|
|
_play_particle(id, offset, global)
|
|
Network._send_actor_action(actor_id, "_play_particle", [id, offset, global], false)
|
|
|
|
func _play_particle(id, offset, global):
|
|
if not PARTICLE_DATA.keys().has(id): return
|
|
var p = PARTICLE_DATA[id].instance()
|
|
add_child(p)
|
|
|
|
if not global:
|
|
p.translation = offset
|
|
else :
|
|
p.set_as_toplevel(true)
|
|
p.global_transform.origin = offset
|
|
|
|
p.emitting = true
|
|
yield (get_tree().create_timer(p.lifetime + 0.1), "timeout")
|
|
p.queue_free()
|
|
|
|
|
|
|
|
|
|
|
|
func _on_water_detect_area_entered(area):
|
|
if gravity_disable: return
|
|
if area.is_in_group("water"):
|
|
_kill()
|
|
|
|
func _kill(skip_anim = false):
|
|
if not controlled: return
|
|
|
|
death_counter += 1
|
|
if death_counter >= 10:
|
|
if not skip_anim: PlayerData._send_notification("too many deaths in a row! sending to spawn...", 1)
|
|
else : PlayerData._send_notification("returning to spawn", 1)
|
|
|
|
world._enter_zone("main_zone", - 1)
|
|
PlayerData.player_saved_zone = "main_zone"
|
|
PlayerData.player_saved_zone_owner = - 1
|
|
last_valid_pos = world.map.spawn_position.global_transform.origin
|
|
death_counter = 0
|
|
|
|
if state == STATES.FISHING or state == STATES.FISHING_CAST or state == STATES.FISHING_CAST:
|
|
_enter_state(STATES.FISHING_CANCEL)
|
|
|
|
cam_push = 0.0
|
|
gravity_disable = true
|
|
|
|
if not skip_anim:
|
|
_enter_animation("drown", true, true)
|
|
_sync_sfx("drown")
|
|
_sync_particle("splash", global_transform.origin, true)
|
|
|
|
SceneTransition._fake_scene_change()
|
|
yield (SceneTransition, "_finished")
|
|
global_transform.origin = last_valid_pos + Vector3(0, 0.5, 0)
|
|
yield (get_tree().create_timer(0.3), "timeout")
|
|
gravity_disable = false
|
|
_enter_state(0)
|
|
_exit_animation()
|
|
|
|
|
|
|
|
|
|
|
|
func _consume_item(id):
|
|
if state != STATES.DEFAULT: return
|
|
_enter_state(STATES.EMOTING)
|
|
|
|
consume_on_state_change = held_item["ref"]
|
|
_enter_animation("drink", false, true, STATES.CONSUME_ITEM, true)
|
|
|
|
var sfx = "drink"
|
|
|
|
match id:
|
|
"growth": player_scale = clamp(player_scale + 0.4, 0.1, 100)
|
|
"shrink": player_scale = clamp(player_scale - 0.1, 0.1, 100)
|
|
"revert":
|
|
player_scale = 1.0
|
|
drunk_timer = max(drunk_timer - 9000, 0)
|
|
sfx = "drink_nocap"
|
|
"speed":
|
|
boost_timer = 18000
|
|
boost_amt = 1.3
|
|
sfx = "drink_nocap"
|
|
"speed_burst":
|
|
boost_timer = 900
|
|
boost_amt = 4.0
|
|
sfx = "drink_nocap"
|
|
"catch":
|
|
catch_drink_timer = 18000
|
|
catch_drink_boost = 1.15
|
|
catch_drink_reel = 1.25
|
|
catch_drink_xp = 1.0
|
|
catch_drink_tier = 1
|
|
catch_drink_gold_add = Vector2(1, 10)
|
|
catch_drink_gold_percent = 0.0
|
|
"catch_big":
|
|
catch_drink_timer = 18000
|
|
catch_drink_boost = 1.3
|
|
catch_drink_reel = 1.45
|
|
catch_drink_xp = 1.0
|
|
catch_drink_tier = 2
|
|
catch_drink_gold_add = Vector2(10, 50)
|
|
catch_drink_gold_percent = 0.25
|
|
"catch_deluxe":
|
|
catch_drink_timer = 18000
|
|
catch_drink_boost = 1.3
|
|
catch_drink_reel = 1.45
|
|
catch_drink_xp = 1.25
|
|
catch_drink_tier = 3
|
|
catch_drink_gold_add = Vector2(0, 0)
|
|
catch_drink_gold_percent = 0.0
|
|
"beer":
|
|
drunk_timer += 9000
|
|
drunk_timer = clamp(drunk_timer, 0, 50000)
|
|
"beer_big":
|
|
drunk_timer += 42000
|
|
drunk_timer = clamp(drunk_timer, 0, 50000)
|
|
sfx = "drink_nocap"
|
|
|
|
_sync_sfx(sfx)
|
|
|
|
|
|
|
|
func _open_chest(rare = false):
|
|
if state != STATES.DEFAULT: return
|
|
|
|
consume_on_state_change = held_item["ref"]
|
|
_enter_state(STATES.CONSUME_ITEM)
|
|
|
|
var cosm = PlayerData._get_unowned_cosmetic()
|
|
if cosm != null: PlayerData._unlock_cosmetic(cosm)
|
|
else :
|
|
PlayerData._send_notification("You found 100 dollars inside the chest!")
|
|
PlayerData.money += 100
|
|
|
|
func _open_ringbox():
|
|
if state != STATES.DEFAULT: return
|
|
|
|
consume_on_state_change = held_item["ref"]
|
|
_enter_state(STATES.CONSUME_ITEM)
|
|
|
|
if not PlayerData.cosmetics_unlocked.has("accessory_ring"): PlayerData._unlock_cosmetic("accessory_ring")
|
|
else :
|
|
PlayerData._send_notification("You already have a ring unlocked... Obtained $1000 instead.")
|
|
PlayerData.money += 1000
|
|
|
|
|
|
|
|
func _scratch_off(type):
|
|
_enter_state(STATES.GUITAR)
|
|
hud._open_minigame("scratch_off", {"type": type})
|
|
var _win = yield (hud, "_minigame_finished")
|
|
yield (get_tree().create_timer(0.15), "timeout")
|
|
_enter_state(STATES.DEFAULT)
|
|
|
|
consume_on_state_change = held_item["ref"]
|
|
_enter_state(STATES.CONSUME_ITEM)
|
|
|
|
if not _win:
|
|
_sync_face_emote("angry")
|
|
_sync_sfx("rip")
|
|
else :
|
|
_sync_face_emote("happy")
|
|
|
|
|
|
|
|
|
|
|
|
func _mushroom_bounce():
|
|
if not controlled: return
|
|
ignore_snap = 10
|
|
var bounce_horz = 16.0 if direction != Vector3.ZERO else 0.0
|
|
var bounce_vert = 32.0
|
|
gravity_vec = Vector3.ZERO
|
|
gravity_vec.x += (direction.normalized() * bounce_horz).x
|
|
gravity_vec.z += (direction.normalized() * bounce_horz).z
|
|
gravity_vec.y += bounce_vert
|
|
animation_data["mushroom"] = true
|
|
|
|
|
|
|
|
|
|
|
|
func _sync_sfx(id, position = null, pitch = 1.0, delay = 0.0):
|
|
if not controlled: return
|
|
if delay > 0.0: yield (get_tree().create_timer(delay), "timeout")
|
|
|
|
_play_sfx(id, position, pitch)
|
|
Network._send_actor_action(actor_id, "_play_sfx", [id, position, pitch], false)
|
|
|
|
func _play_sfx(id, position = null, pitch = 1.0):
|
|
if not in_zone or not visible: return
|
|
sound_manager._play_sound(id, position, pitch)
|
|
print("playing sfx ", id)
|
|
|
|
func _process_sounds():
|
|
|
|
|
|
|
|
|
|
if $sound_manager / dive_scrape.playing != animation_data["dive_scrape"]: $sound_manager / dive_scrape.playing = animation_data["dive_scrape"] and in_zone
|
|
if $sound_manager / reel_slow.stream_paused == animation_data["reel_slow"]: $sound_manager / reel_slow.stream_paused = not animation_data["reel_slow"] and in_zone
|
|
if $sound_manager / reel_fast.playing != animation_data["reel_fast"]: $sound_manager / reel_fast.playing = animation_data["reel_fast"] and in_zone
|
|
|
|
|
|
|
|
|
|
|
|
func _on_rain_timer_timeout():
|
|
if not controlled: return
|
|
|
|
var rain = false
|
|
for child in $raincloud_check.get_overlapping_areas():
|
|
if child.is_in_group("rain_cloud"):
|
|
rain = true
|
|
|
|
if rain != in_rain:
|
|
in_rain = rain
|
|
PlayerData.emit_signal("_rain_toggle", in_rain)
|
|
|
|
if not in_rain: Network.set_rich_presence("#default")
|
|
else : Network.set_rich_presence("#rain")
|
|
|
|
|
|
|
|
|
|
|
|
func _wag():
|
|
animation_data["wagging"] = not animation_data["wagging"]
|
|
|
|
func _paint(size, color):
|
|
if not controlled: return
|
|
|
|
var in_zone = false
|
|
for area in $paint_node / Area.get_overlapping_areas():
|
|
if area.is_in_group("canvas"): in_zone = true
|
|
if not in_zone: PlayerData._send_notification("mouse must be on a drawing zone!", 1)
|
|
|
|
$paint_node.size = size
|
|
$paint_node.color = color
|
|
$paint_node.drawing = true
|
|
|
|
func _paint_stop():
|
|
if not controlled: return
|
|
$paint_node.drawing = false
|
|
PlayerData.emit_signal("_chalk_send")
|
|
|
|
func _metal_detect_begin():
|
|
pass
|
|
|
|
func _metaldetect_update():
|
|
if not controlled or held_item.id == "":
|
|
return
|
|
|
|
var idata = Globals.item_data[held_item["id"]]["file"]
|
|
if not idata.detect_item:
|
|
return
|
|
|
|
var alert_level = 0
|
|
for b in $detection_zones / metal_detect_far.get_overlapping_bodies():
|
|
if b.is_in_group("metal_spawn"):
|
|
if abs(b.global_transform.origin.y - global_transform.origin.y) > 3.5: continue
|
|
alert_level = b.global_transform.origin.distance_to(global_transform.origin)
|
|
|
|
metal_detect_alert_level = alert_level
|
|
|
|
if alert_level > 0: _metal_detect_beep()
|
|
|
|
func _metal_detect_beep():
|
|
var new_cd = ceil(max(metal_detect_alert_level * 0.5, 1))
|
|
|
|
if abs(new_cd - metal_detect_alert_cd) > 4: metal_detect_alert_cd = 0
|
|
|
|
metal_detect_alert_cd -= 1
|
|
if metal_detect_alert_cd > 0: return
|
|
|
|
metal_detect_alert_cd = new_cd
|
|
|
|
var pitch = max(6.0 - metal_detect_alert_level * 0.3, 0.5)
|
|
|
|
$metaldetect_dot.modulate.a = 1.0
|
|
if metal_detect_flop: _sync_sfx("md_beep_slowb", null, pitch)
|
|
else : _sync_sfx("md_beep_slow", null, pitch)
|
|
metal_detect_flop = not metal_detect_flop
|
|
|
|
func _on_metal_detect_consume_body_entered(b):
|
|
if not controlled or held_item.id == "": return
|
|
|
|
var idata = Globals.item_data[held_item["id"]]["file"]
|
|
if not idata.detect_item: return
|
|
|
|
if b.is_in_group("metal_spawn"):
|
|
b._reveal()
|
|
|
|
func _on_image_update_timeout():
|
|
if not controlled or dead_actor: return
|
|
_update_held_item(held_item)
|
|
Network._send_actor_action(actor_id, "_update_held_item", [held_item], false)
|
|
|
|
func _real_step(run = false):
|
|
if anim_tree.get("parameters/dive/blend_amount") > 0.2 or anim_tree.get("parameters/movement/blend_amount") < 0.8: return
|
|
if not is_on_floor(): return
|
|
var sfx = "step" if not run else "step_run"
|
|
if boost_amt > 1.0 and boost_timer > 1: sfx = "step_fastrun"
|
|
_sync_sfx(sfx)
|
|
|
|
|
|
|
|
func _play_guitar():
|
|
_enter_state(STATES.GUITAR)
|
|
hud._open_minigame("guitar")
|
|
var _win = yield (hud, "_minigame_finished")
|
|
yield (get_tree().create_timer(0.15), "timeout")
|
|
_enter_state(STATES.DEFAULT)
|
|
|
|
func _strum_guitar(string, fret, volume):
|
|
_sync_strum(string, fret, volume)
|
|
Network._send_actor_action(actor_id, "_sync_strum", [string, fret, volume])
|
|
|
|
animation_data["land"] = clamp(animation_data["land"] + 0.06, 0.0, 0.3)
|
|
_sync_face_emote("strum")
|
|
if randf() < 0.05:
|
|
_sync_particle("music")
|
|
|
|
func _sync_strum(string, fret, volume):
|
|
if not in_zone or not visible: return
|
|
$guitar_sounds.get_child(string)._play_fret(fret, false, volume)
|
|
|
|
func _hammer_string(string, fret):
|
|
_sync_hammer(string, fret)
|
|
Network._send_actor_action(actor_id, "_sync_hammer", [string, fret])
|
|
|
|
func _sync_hammer(string, fret):
|
|
if not in_zone or not visible: return
|
|
$guitar_sounds.get_child(string)._hammer_fret(fret)
|
|
|
|
func _bark():
|
|
if not controlled: return
|
|
var bark_id = "bark_dog"
|
|
bark_id = {
|
|
"species_cat": ["bark_cat", "growl_cat", "whine_cat"],
|
|
"species_dog": ["bark_dog", "growl_dog", "whine_dog"],
|
|
}[PlayerData.cosmetics_equipped.species]
|
|
|
|
var type = 0
|
|
if Input.is_action_pressed("move_sneak"):
|
|
_sync_face_emote("growl")
|
|
type = 1
|
|
elif Input.is_action_pressed("move_walk"):
|
|
_sync_face_emote("whine")
|
|
type = 2
|
|
else :
|
|
_sync_face_emote("bark")
|
|
|
|
bark_id = bark_id[type]
|
|
_sync_sfx(bark_id)
|
|
|
|
func _kiss():
|
|
if not controlled: return
|
|
|
|
animation_data["land"] = animation_data["land"] + 0.2
|
|
_sync_face_emote("kiss")
|
|
_sync_sfx("kiss")
|
|
_sync_particle("kiss")
|
|
|
|
func _punch(type = 0):
|
|
if not controlled or item_cooldown > 0: return
|
|
item_cooldown = 30
|
|
|
|
animation_data["land"] = animation_data["land"] + 1.0
|
|
for b in $detection_zones / punch.get_overlapping_bodies():
|
|
if b.is_in_group("player") and b != self and not b.controlled:
|
|
Network._send_P2P_Packet({"type": "player_punch", "from": global_transform.origin, "player": owner_id, "punch_type": type}, str(b.owner_id), 2)
|
|
|
|
_sync_face_emote("punch")
|
|
_sync_sfx("punch")
|
|
_sync_punch()
|
|
Network._send_actor_action(actor_id, "_sync_punch")
|
|
|
|
func _sync_punch():
|
|
$emotion_particles / punch_particles.restart()
|
|
$emotion_particles / punchb_particles.restart()
|
|
|
|
func _punched(from, type):
|
|
if not controlled: return
|
|
|
|
if OptionsMenu.punchable: return
|
|
|
|
var dir = (global_transform.origin - from).normalized()
|
|
|
|
ignore_snap = 10
|
|
var bounce_horz = 4.0
|
|
var bounce_vert = 8.0
|
|
|
|
match type:
|
|
0:
|
|
bounce_horz = 4.0
|
|
bounce_vert = 8.0
|
|
1:
|
|
bounce_horz = 12.0
|
|
bounce_vert = 24.0
|
|
|
|
gravity_vec = Vector3.ZERO
|
|
gravity_vec.x += (dir.normalized() * bounce_horz).x
|
|
gravity_vec.z += (dir.normalized() * bounce_horz).z
|
|
gravity_vec.y += bounce_vert
|
|
|
|
_sync_face_emote("angry")
|
|
|
|
func _tambourine():
|
|
_sync_sfx("tambourine")
|
|
|
|
animation_data["land"] = clamp(animation_data["land"] + 0.14, 0.0, 0.3)
|
|
_sync_face_emote("strum")
|
|
if randf() < 0.25:
|
|
_sync_particle("music")
|
|
|
|
func _on_cosmetic_refresh_timeout():
|
|
if not controlled: return
|
|
_refresh_cosmetics()
|
|
|
|
func _refresh_cosmetics():
|
|
if not controlled: return
|
|
yield (get_tree().create_timer(1.0), "timeout")
|
|
var new = PlayerData.cosmetics_equipped.duplicate()
|
|
if not dead_actor: Network._send_actor_action(actor_id, "_update_cosmetics", [new])
|
|
|
|
func _return_to_spawn():
|
|
if not controlled: return
|
|
death_counter = 11
|
|
_kill(true)
|
|
|
|
func _item_removal(ref):
|
|
print("Sold Item")
|
|
if held_item.keys().has("ref") and held_item["ref"] == ref: _equip_item(PlayerData.FALLBACK_ITEM.duplicate())
|