diff --git a/project.godot b/project.godot index 1c15ea6..53fc327 100644 --- a/project.godot +++ b/project.godot @@ -59,6 +59,8 @@ primary_ability=[ Object(InputEventKey,"resource_local_to_scene":false,"resource ] hero_0_boost=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) ] +primary_mouse=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) + ] [rendering] diff --git a/scripts/hero_select.gd b/scripts/hero_select.gd index 3b998d3..5fd34df 100644 --- a/scripts/hero_select.gd +++ b/scripts/hero_select.gd @@ -15,7 +15,7 @@ const hero_text = [ "LUST.\n\nYou attract nearby heroes.\n\nPress E to switch to repelling them.", "GENEROSITY.\n\nMake contact with a friend to boost their speed.\n\nPress E to separate.", "PATIENCE.\n\nHold left mouse button on an enemy to slow them down.\n\nPress E to delete someone else's building (costs charge).", - "PRIDE.\n\nClick to build portal. Click again to build its partner.\n\nYou can build multiple portal sets.", + "PRIDE.\n\nDrag on enemies to bully them around.\n\nClick to build a portal. Click again to build its partner (costs charge).", ] func _ready(): diff --git a/scripts/heroes/0.gd b/scripts/heroes/0.gd index 7a154be..db67e4b 100644 --- a/scripts/heroes/0.gd +++ b/scripts/heroes/0.gd @@ -24,7 +24,7 @@ func control_player(state): var boost_strength = 2 var boost_drain = 25 # Recall increased charge must be factored in var cost = boost_drain * state.step - if Input.is_action_pressed("primary_action") and switch_charge > cost: + if Input.is_action_pressed("hero_0_boost") and switch_charge > cost: walk_speed *= 2 air_accel *= 2 switch_charge -= cost diff --git a/scripts/heroes/1_wall.gd b/scripts/heroes/1_wall.gd index f359e33..9c87f84 100644 --- a/scripts/heroes/1_wall.gd +++ b/scripts/heroes/1_wall.gd @@ -7,7 +7,7 @@ func _process(delta): if being_touched > 0: maker_node.switch_charge += touch_charge * delta -func init(maker): +func init(maker, index): for player in get_node("/root/Level/Players").get_children(): player.connect("body_entered", self, "count_bodies", [player, 1]) @@ -27,7 +27,7 @@ func init(maker): mat.albedo_color = color get_node("MeshInstance").set_surface_material(0, mat) - .init(maker) + .init(maker, index) func count_bodies(with, player, delta): if with == self: diff --git a/scripts/heroes/4.gd b/scripts/heroes/4.gd index 77899f7..0a5a89f 100644 --- a/scripts/heroes/4.gd +++ b/scripts/heroes/4.gd @@ -29,8 +29,7 @@ func _process(delta): get_node("TPCamera").cam_smooth_movement = true if Input.is_action_just_pressed("primary_ability"): - var look_ray = get_node("TPCamera/Camera/Ray") - var looking_at = look_ray.get_collider() + var looking_at = pick() if looking_at.has_method("destroy"): if switch_charge > looking_at.destroy_cost: switch_charge -= looking_at.destroy() diff --git a/scripts/heroes/5.gd b/scripts/heroes/5.gd index ebf9d11..dc53a2d 100644 --- a/scripts/heroes/5.gd +++ b/scripts/heroes/5.gd @@ -6,6 +6,12 @@ var radius = 15 # The spaces make the bracket centered, rather than on of the dots var first_crosshair = " [..." var second_crosshair = "...] " +var no_portal_crosshair = "+" +var portal_cost = 20 + +var flicking = null +var flick_charge = 3 +var flick_strength = 4 # --- Godot overrides --- @@ -17,10 +23,30 @@ func _ready(): func _process(delta): if is_network_master(): - placement.place_input(radius) var is_second = placement.placed.size() % 2 != 0 - var crosshair = second_crosshair if is_second else first_crosshair + var portal_crosshair = second_crosshair if is_second else first_crosshair + var crosshair = no_portal_crosshair if switch_charge < portal_cost else portal_crosshair get_node("MasterOnly/Crosshair").set_text(crosshair) + if switch_charge > portal_cost or is_second: + if placement.place_input(radius, true) and is_second: + switch_charge -= portal_cost + + if Input.is_action_just_pressed("primary_mouse"): + var pick = pick_by_friendly(false) + if pick: + flicking = pick + if flicking and Input.is_action_just_released("primary_mouse"): + var aim = get_node("Yaw/Pitch").get_global_transform().basis + var forwards = -aim[2] + var distance = (flicking.translation - translation).length() + forwards *= distance + var towards = translation + forwards + var gravity = PhysicsServer.area_get_param(get_world().get_space(), PhysicsServer.AREA_PARAM_GRAVITY_VECTOR) + # Automatically account for gravity, so as to make UI more intuitive + towards -= gravity + rpc("flick", flicking.get_name(), towards) + flicking = null + switch_charge += flick_charge func _exit_tree(): ._exit_tree() @@ -31,3 +57,10 @@ func _exit_tree(): # --- Own --- +sync func flick(player_id, towards): + var who = $"/root/Level/Players".get_node(player_id) + if who.is_network_master(): + var direction = towards - who.translation + var impulse = direction.normalized() * flick_strength * who.get_mass() + who.apply_impulse(Vector3(), impulse) + diff --git a/scripts/heroes/5_portal.gd b/scripts/heroes/5_portal.gd index 92fcdaa..239e6ea 100644 --- a/scripts/heroes/5_portal.gd +++ b/scripts/heroes/5_portal.gd @@ -1,8 +1,7 @@ extends "res://scripts/placeable.gd" -var portal_charge = 15 +var portal_charge = -5 var other -var index var enemy_colors = [ Color("#d14013"), @@ -24,10 +23,8 @@ func _exit_tree(): maker_node.placement.placed.remove(index - 1) other.queue_free() -func init(maker): +func init(maker, index): - var maker_portals = maker.placement.placed - index = maker_portals.size() # No -1, because we haven't actually been added to the array yet # If index is odd, we're the second (1, 3...), if even, first (0, 4...) var second = index % 2 != 0 var is_friend = util.is_friendly(maker) @@ -40,7 +37,7 @@ func init(maker): mat.albedo_color = color get_node("MeshInstance").set_surface_material(0, mat) - .init(maker) + .init(maker, index) func place(): .place() @@ -57,12 +54,13 @@ func player_collided(with, player): func portal(player): if player.player_info.is_right_team == maker_node.player_info.is_right_team: if other: - var spawn_distance = 1.75 - # Find a sane place to spawn - # -Z is in the direction of the portal - # X is enough away from the portal to avoid infinite loop - # With both axes, gravity could never bring us to hit the portal - var to = other.to_global(Vector3(spawn_distance,0,-spawn_distance)) - player.set_translation(to) - maker_node.switch_charge += portal_charge + if maker_node.switch_charge > -portal_charge: + var spawn_distance = 1.75 + # Find a sane place to spawn + # -Z is in the direction of the portal + # X is enough away from the portal to avoid infinite loop + # With both axes, gravity could never bring us to hit the portal + var to = other.to_global(Vector3(spawn_distance,0,-spawn_distance)) + player.set_translation(to) + maker_node.switch_charge += portal_charge diff --git a/scripts/placeable.gd b/scripts/placeable.gd index a842de4..13853d0 100644 --- a/scripts/placeable.gd +++ b/scripts/placeable.gd @@ -3,12 +3,14 @@ extends StaticBody var maker_node var material var destroy_cost = 20 +var index func _ready(): get_node("CollisionShape").disabled = true -func init(maker): +func init(maker, index): maker_node = maker + self.index = index material = get_node("MeshInstance").get_surface_material(0) if not material: @@ -23,7 +25,7 @@ func place(): material.flags_transparent = false func destroy(): - queue_free() + maker_node.placement.remove_placed(index) return destroy_cost func make_last(): diff --git a/scripts/placement.gd b/scripts/placement.gd index 7ca1053..ca4a9e8 100644 --- a/scripts/placement.gd +++ b/scripts/placement.gd @@ -31,12 +31,12 @@ master func request_placed(): for node in placed: rpc_id(get_tree().get_rpc_sender_id(), "slave_place", node.transform) -func place_input(radius=-1): +func place_input(radius=-1, require_ghost=false): # We allow you to just click to place, without needing to press E var confirm = Input.is_action_just_pressed(confirm_action) - if Input.is_action_just_pressed(start_action) or (confirm and not is_placing): + if Input.is_action_just_pressed(start_action) or (confirm and not is_placing and not require_ghost): # Press button twice to cancel if is_placing: # We changed our mind, delete the placing wall @@ -52,7 +52,7 @@ func place_input(radius=-1): if pick != -1: rpc("remove_placed", pick) - if is_placing or confirm: + if is_placing: position_placement(placing_node) if radius > 0: # A radius is specified var distance = placing_node.get_translation() - player.get_translation() @@ -62,10 +62,12 @@ func place_input(radius=-1): else: placing_node.within_range() - if confirm: + if (confirm and not require_ghost) or (confirm and is_placing): # Order matters here: confirm_placement resets placing_node so we have to do anything with it first rpc("slave_place", placing_node.transform) confirm_placement(placing_node) + return true + return false func confirm_placement(node, tf=null): if tf: @@ -130,7 +132,6 @@ sync func remove_placed(index): func create(): var node = scene.instance() player.get_node("/root/Level").add_child(node) - # We have to call_deferred because we're `load`ing instead of `preload`ing. TODO: preload? - node.init(player) + node.init(player, placed.size()) return node diff --git a/scripts/player.gd b/scripts/player.gd index db01723..d375647 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -297,10 +297,22 @@ func quit(): # These aren't used by vanilla player, but are used by heroes in common -func pick_from(group): +func pick(): var look_ray = get_node("TPCamera/Camera/Ray") - var looking_at = look_ray.get_collider() - var result = group.find(looking_at) - return result + return look_ray.get_collider() + +func pick_from(group): + return group.find(pick()) + +func pick_player(): + var players = get_node("/root/Level/Players").get_children() + return players[pick_from(players)] + +func pick_by_friendly(pick_friendlies): + var pick = pick_player() + if (pick.player_info.is_right_team == player_info.is_right_team) == pick_friendlies: + return pick + else: + return null # =========