summaryrefslogtreecommitdiff
path: root/godot/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'godot/scripts')
-rw-r--r--godot/scripts/CharacterAIManager.gd18
-rw-r--r--godot/scripts/GameBase.gd3
-rw-r--r--godot/scripts/Server.gd26
-rw-r--r--godot/scripts/World.gd7
-rw-r--r--godot/scripts/ballistics/Cannonball.gd11
-rw-r--r--godot/scripts/characters/Idle.gd2
-rw-r--r--godot/scripts/characters/ManCannon.gd107
-rw-r--r--godot/scripts/characters/NetworkedCharacter.gd14
-rw-r--r--godot/scripts/characters/player_controller_new.gd164
-rw-r--r--godot/scripts/fsm/State.gd22
-rw-r--r--godot/scripts/fsm/StateMachine.gd35
-rw-r--r--godot/scripts/machines/Cannon.gd27
-rw-r--r--godot/scripts/vehicles/Gunboat.gd10
13 files changed, 376 insertions, 70 deletions
diff --git a/godot/scripts/CharacterAIManager.gd b/godot/scripts/CharacterAIManager.gd
index fb86a48..61d38ae 100644
--- a/godot/scripts/CharacterAIManager.gd
+++ b/godot/scripts/CharacterAIManager.gd
@@ -4,7 +4,7 @@ var calcs_per_tick: int = 15
var request_queue: Array = [] #array of dictionaries
var cur_req: Dictionary
var cur_req_args: Dictionary
-var WORLD_MAP_RID
+var WORLD_MAP_RID: RID
enum Task {PATHFIND, FINDITEM}
@@ -13,6 +13,9 @@ enum Task {PATHFIND, FINDITEM}
func _ready():
pass # Replace with function body.
+func set_rid(id: RID) -> void:
+ WORLD_MAP_RID = id
+
func _physics_process(_delta):
for i in calcs_per_tick:
if len(request_queue) == 0:
@@ -22,7 +25,20 @@ func _physics_process(_delta):
if cur_req["type"] == Task.PATHFIND:
var dest_vec: Vector3 = cur_req_args["dest"] if cur_req_args["obj"] == null else cur_req_args["obj"].global_transform.origin
var path: PoolVector3Array = NavigationServer.map_get_path(WORLD_MAP_RID, cur_req["char"].global_transform.origin, dest_vec, cur_req_args["optimize"])
+ cur_req["char"].ai_set_path_array(path)
+ elif cur_req["type"] == Task.FINDITEM:
+ var bodies = cur_req["char"].get_node("AISearchArea").get_overlapping_bodies()
+ for body in bodies:
+ if body.name.begins_with(cur_req_args["objtype"]):
+ var path: PoolVector3Array = NavigationServer.map_get_path(WORLD_MAP_RID, cur_req["char"].global_transform.origin, body.global_transform.origin, cur_req_args["optimize"])
+ cur_req["char"].ai_set_path_target(body.global_transform.origin)
+ #cur_req["char"].ai_set_path_array(path)
+ cur_req["char"].ai_set_look_status(body, "TRACK")
+ return
#will request a path from character to dest_g, or to the global origin of obj if passed
func request_find_path(character: NetChar, dest_g: Vector3, precise: bool, obj: Spatial = null) -> void:
request_queue.append({"char" : character, "type" : Task.PATHFIND, "args" : {"dest" : dest_g, "obj" : obj, "optimize" : !precise}})
+
+func request_find_object(character: NetChar, object: String, radius: float, precise: bool):
+ request_queue.append({"char" : character, "type" : Task.FINDITEM, "args" : {"objtype" : object, "radius" : radius, "optimize" : !precise}})
diff --git a/godot/scripts/GameBase.gd b/godot/scripts/GameBase.gd
index 9f24d7b..abc269f 100644
--- a/godot/scripts/GameBase.gd
+++ b/godot/scripts/GameBase.gd
@@ -9,6 +9,7 @@ var player_name : String
var player_team : String
var player_char = null
onready var cam = $PLAYERCAM
+onready var hud = $HUD
var players_info = {} #dictionary of id : name, team, ping, etc.
@@ -77,7 +78,7 @@ remotesync func game_hitsound():
remotesync func game_killsound():
$HUD.ui_play_killsound()
-func select_character(dest):
+func request_select_character(dest):
if player_char == null:
rpc_id(1, "_call_on_server", "_client_request_change_character", {"id" : client_id, "current_char_name" : "NULL", "char_name" : dest})
else:
diff --git a/godot/scripts/Server.gd b/godot/scripts/Server.gd
index b4b0a28..e360703 100644
--- a/godot/scripts/Server.gd
+++ b/godot/scripts/Server.gd
@@ -30,7 +30,15 @@ func start_server(_server_name: String, _motd: String, max_players: int, map_pat
server_name = _server_name
motd = _motd
player_limit = max_players
-
+
+ server_enet = NetworkedMultiplayerENet.new()
+ var srv_stat = server_enet.create_server(port, max_players)
+ if srv_stat != OK:
+ print_line("Error creating server. Code: "+str(srv_stat))
+ stop_server()
+ return
+ tree.set_network_peer(server_enet)
+
world = load(map_path)
if world:
world = world.instance()
@@ -43,14 +51,6 @@ func start_server(_server_name: String, _motd: String, max_players: int, map_pat
world.client_id = 1
- server_enet = NetworkedMultiplayerENet.new()
- var srv_stat = server_enet.create_server(port, max_players)
- if srv_stat != OK:
- print_line("Error creating server. Code: "+str(srv_stat))
- stop_server()
- return
- tree.set_network_peer(server_enet)
-
print_line("Server started successfully.")
func stop_server():
@@ -125,3 +125,11 @@ func _send_chat(arguments):
arguments["name"]=connected_players[arguments["id"]][0]
print_line(arguments["name"]+ ": " + arguments["msg"])
world.rpc("game_chat_msg", arguments["name"]+ ": " + arguments["msg"])
+
+func _set_ai_state(args):
+ var charname: String = args[0]
+ var state: String = args[1]
+ print(args)
+ var man: NetChar = world.get_node("PLAYERS/"+charname)
+ if man:
+ man.ai_set_state(state)
diff --git a/godot/scripts/World.gd b/godot/scripts/World.gd
index 01df1b5..90b3cf7 100644
--- a/godot/scripts/World.gd
+++ b/godot/scripts/World.gd
@@ -7,7 +7,7 @@ onready var pathfinder = get_node("PLAYERS/Player2")
var path = []
var map_rids
var client_id
-var player_char
+var player_char: NetChar
var players_info = {}
var WORLD_MAP_RID : RID
@@ -23,12 +23,13 @@ func _ready():
#merge all nav meshes onto the main map
yield(get_tree().create_timer(1.0), "timeout")
WORLD_MAP_RID = get_world().get_navigation_map()
- find_path()
+ CharacterAIManager.set_rid(WORLD_MAP_RID)
+ #find_path()
remotesync func update_players_info(info):
players_info = info
-remote func _call_on_server(function, arguments):
+remotesync func _call_on_server(function, arguments):
print('Remote server call: ' + function)
$Server.call(function, arguments)
diff --git a/godot/scripts/ballistics/Cannonball.gd b/godot/scripts/ballistics/Cannonball.gd
index b41f104..5e6b84d 100644
--- a/godot/scripts/ballistics/Cannonball.gd
+++ b/godot/scripts/ballistics/Cannonball.gd
@@ -3,9 +3,12 @@ extends "res://scripts/ballistics/NetworkedProjectile.gd"
export var drag_constant: float = 0.3
var damage_exceptions = []
var oldvel: Vector3
+var oldoldvel: Vector3
+const inventory_name: String = "cannonball"
func _physics_process(_delta):
if is_network_master():
+ oldoldvel = oldvel
oldvel = linear_velocity
add_force(-1*linear_velocity*drag_constant, Vector3.ZERO)
if global_transform.origin.y < -20:
@@ -15,10 +18,6 @@ func get_init_info():
return {"linear_velocity" : linear_velocity, "angular_velocity" : angular_velocity, "oldvel" : oldvel, "shooter" : shooter, "shooter_id" : shooter_id}
func _on_collision(body):
- if is_network_master() and body.has_method("load_cannonball") and !body.loaded:
- body.rpc("load_cannonball")
- rpc("net_remove")
- return
- if is_network_master() and oldvel.length() > 20 and !damage_exceptions.has(body) and body.has_method("damage"):
- body.rpc("damage", oldvel.length(), "BLUNT", [shooter_id, shooter], "using 'cannon'")
+ if is_network_master() and oldoldvel.length() > 20 and !damage_exceptions.has(body) and body.has_method("damage"):
+ body.rpc("damage", oldoldvel.length(), "BLUNT", [shooter_id, shooter], "using 'cannon'")
damage_exceptions.append(body)
diff --git a/godot/scripts/characters/Idle.gd b/godot/scripts/characters/Idle.gd
new file mode 100644
index 0000000..4be00e4
--- /dev/null
+++ b/godot/scripts/characters/Idle.gd
@@ -0,0 +1,2 @@
+extends State
+
diff --git a/godot/scripts/characters/ManCannon.gd b/godot/scripts/characters/ManCannon.gd
new file mode 100644
index 0000000..b4d111c
--- /dev/null
+++ b/godot/scripts/characters/ManCannon.gd
@@ -0,0 +1,107 @@
+extends State
+
+enum ManCannonStates { INITIAL, OPERATE_CANNON, MOVE_TO_CANNON, FIND_CANNONBALL }
+var ai_substate: int
+var path_requested: bool = false
+var retry_timer: float = 0.0
+var searching_for: String
+
+var cannon: NetMachine
+
+# Corresponds to the `_process()` callback.
+func update(delta: float) -> void:
+ retry_timer -= delta
+
+# Virtual function. Corresponds to the `_physics_process()` callback.
+func physics_update(_delta: float) -> void:
+ match ai_substate:
+ ManCannonStates.INITIAL:
+ _state_initial()
+ ManCannonStates.MOVE_TO_CANNON:
+ _state_move_to_cannon()
+ ManCannonStates.FIND_CANNONBALL:
+ _state_find_cannonball()
+ ManCannonStates.OPERATE_CANNON:
+ _state_operate_cannon()
+
+func _state_initial() -> void:
+ if cannon.loaded:
+ change_substate(ManCannonStates.MOVE_TO_CANNON)
+ else:
+ change_substate(ManCannonStates.FIND_CANNONBALL)
+
+func _state_move_to_cannon() -> void:
+ if !path_requested:
+ #CharacterAIManager.request_find_path(owner, Vector3.ZERO, true, cannon.get_node("AINavPoint"))
+ owner.ai_set_path_target(cannon.get_node("AINavPoint").global_transform.origin)
+ owner.ai_set_look_status(cannon.steer_area, "TRACK")
+ path_requested = true
+ if (owner.global_transform.origin - cannon.get_node("AINavPoint").global_transform.origin).length_squared() > 4:
+ owner.ai_set_path_target(cannon.get_node("AINavPoint").global_transform.origin)
+ if retry_timer <= 0 and owner.use_ray.is_colliding():
+ if owner.use_ray.get_collider() == cannon.steer_area:
+ owner.use_held = false
+ owner.initiate_use()
+ if !cannon.loaded:
+ owner.use_held = true
+ retry_timer = 3.1
+
+ if owner.machine == cannon:
+ owner.ai_set_look_status(null, "NONE")
+ retry_timer = 1.0
+ change_substate(ManCannonStates.OPERATE_CANNON)
+
+func _state_find_cannonball() -> void:
+ #CHECK FOR BALL BOX FIRST! /setaistate Player ManCannon
+ if !path_requested:
+ CharacterAIManager.request_find_object(owner, "BallBarrel", 50, true)
+ searching_for = "BallBarrel"
+ path_requested = true
+ #if !path_requested:
+ # CharacterAIManager.request_find_object(owner, "Cannonball", 50, false)
+ # searching_for = "Cannonball"
+ # path_requested = true
+ if owner.use_ray.is_colliding():
+ if owner.use_ray.get_collider().name.begins_with("UseArea") and owner.use_ray.get_collider().get_parent().name.begins_with(searching_for):
+ owner.initiate_use()
+
+ #cannonball found
+ if owner.inventory["cannonball"] > 0:
+ change_substate(ManCannonStates.MOVE_TO_CANNON)
+
+func _state_operate_cannon() -> void:
+ if owner.machine != cannon: #if control lost
+ if is_instance_valid(cannon):
+ change_substate(ManCannonStates.MOVE_TO_CANNON)
+ else:
+ state_machine.transition_to("Idle")
+ return
+ if retry_timer <= 0.0:
+ cannon.attack1()
+ owner.initiate_use()
+ change_substate(ManCannonStates.FIND_CANNONBALL)
+
+func change_substate(to: int):
+ path_requested = false
+ ai_substate = to
+
+func enter(msg := {}) -> void:
+ retry_timer = 0
+ ai_substate = ManCannonStates.INITIAL
+ if "cannon" in msg.keys():
+ cannon = msg["cannon"]
+ else:
+ if owner.ai_target_machine != null:
+ cannon = owner.ai_target_machine
+ return
+ var bodies = owner.get_node("AISearchArea").get_overlapping_bodies()
+ for body in bodies:
+ if body.name.begins_with("Cannon"):
+ cannon = body
+ return
+ #if cannon not found
+ print("cannon not found")
+ state_machine.transition_to("Idle")
+
+func exit() -> void:
+ pass
diff --git a/godot/scripts/characters/NetworkedCharacter.gd b/godot/scripts/characters/NetworkedCharacter.gd
index c8e90a4..c14d46f 100644
--- a/godot/scripts/characters/NetworkedCharacter.gd
+++ b/godot/scripts/characters/NetworkedCharacter.gd
@@ -15,14 +15,21 @@ var world: Spatial = null
var carrying: bool = false
var carrying_object: NetObject = null
+var loading: bool = false
+var load_target: RigidBody = null
+var load_ammo: String
+
# Control
var controlling_machine: bool = false #whether character is riding/controlling something
var machine: RigidBody = null
-export var is_player: bool = false #whether character is currently controlled by a player
+var is_player: bool = false #whether character is currently controlled by a player
var ladder_m: Spatial = null
+const inventory_caps: Dictionary = {"cannonball" : 1}
+remote var inventory: Dictionary = {"cannonball" : 0} #
+
func get_init_info() -> Dictionary:
- return {"linear_velocity" : linear_velocity, "angular_velocity" : angular_velocity, "controlling_machine" : controlling_machine, "team" : team, "health" : health, "nametag" : $Nametag.text}
+ return {"linear_velocity" : linear_velocity, "angular_velocity" : angular_velocity, "controlling_machine" : controlling_machine, "team" : team, "health" : health, "inventory": inventory, "nametag" : $Nametag.text}
func mp_init(init_info: Dictionary):
for variable in init_info.keys():
@@ -60,11 +67,12 @@ func take_control_of_machine(slave_machine: RigidBody):
controlling_machine = true
func lose_machine():
- if is_network_master(): world.cam.attach(self, "FIRSTPERSON", "./Neck/Head")
+ if is_network_master() and get_network_master() != 1: world.cam.attach(self, "FIRSTPERSON", "./Neck/Head")
controlling_machine = false
machine = null
remotesync func damage(dmg_amt: int, _type: String, shooter: Array, extra: String):
+ print(dmg_amt)
health -= dmg_amt
if health <= 0 and is_network_master():
if shooter[0] != get_network_master() and shooter[0] != 1: world.rpc_id(shooter[0], "game_killsound")
diff --git a/godot/scripts/characters/player_controller_new.gd b/godot/scripts/characters/player_controller_new.gd
index 6e2a28b..b2af75c 100644
--- a/godot/scripts/characters/player_controller_new.gd
+++ b/godot/scripts/characters/player_controller_new.gd
@@ -7,6 +7,7 @@ var mouse_axis: Vector2 = Vector2.ZERO
onready var head: Spatial = $Neck/Head
onready var neck: Spatial = $Neck
onready var melee_ray: RayCast = $"%MeleeRay"
+onready var use_ray: RayCast = $"%UseRay"
onready var gun_ray: RayCast = $Neck/Head/GunRay
onready var carry_point: Position3D = $Neck/Head/CarryPoint
onready var viewmodel: Spatial = $Neck/Head/VIEWMODEL_ARMS
@@ -17,6 +18,7 @@ var direction := Vector3()
var move_axis := Vector2()
var floorspeed := Vector3()
var jumping:bool = false
+var use_held:bool = false
var can_jump:bool = true
onready var nav: NavigationAgent = $NavigationAgent
@@ -37,10 +39,17 @@ var c_friction:float = 4.0
var air_control:float = 0.3
#ai
-var ai_state: String = "IDLE"
+onready var ai_state_machine:StateMachine = get_node("AIStateMachine")
+enum AIStates { IDLE, MAN_CANNON }
+export(AIStates) var ai_state = AIStates.IDLE
+
+export var ai_target_machine_path := NodePath()
+var ai_target_machine: NetMachine = null
var ai_should_pathfind: bool = false
var ai_path_target_global: Vector3 = Vector3.ZERO
+var ai_path_array: Array = []
+const AI_PATH_PROXIM_DIST_SQ: float = 1.0
var ai_look_target: Vector3 = Vector3.ZERO
var ai_should_look: bool = false
@@ -63,6 +72,15 @@ func _ready() -> void:
$"%MeleeRay".add_exception(self)
$"%UseRay".add_exception($AreaDetect)
$"%MeleeRay".add_exception($AreaDetect)
+
+ if ai_target_machine_path:
+ ai_target_machine = get_node(ai_target_machine_path)
+ if get_tree().get_network_unique_id() != 1: #only server needs ai processing
+ get_node("AIStateMachine").queue_free()
+
+ #for playerbody in get_tree().get_nodes_in_group("player"):
+ # if playerbody.team == team and playerbody != self:
+ # add_collision_exception_with(playerbody)
func add_weapon_vm(weapon_vm: Spatial, trfrm: Transform):
viewmodel.get_node("Skeleton/GunBone").add_child(weapon_vm)
@@ -70,10 +88,12 @@ func add_weapon_vm(weapon_vm: Spatial, trfrm: Transform):
# Called every frame. 'delta' is the elapsed time since the previous frame
func _process(_delta: float) -> void:
- if is_player and !world.is_chatting:
+ if is_network_master() and !is_player:
+ pass
+ elif is_player and !world.is_chatting:
+ use_held = Input.is_action_pressed("use")
if Input.is_action_just_pressed("use"):
initiate_use()
-
if controlling_machine:
if Input.is_action_just_pressed("fire"):
machine.attack1()
@@ -121,26 +141,57 @@ func initiate_use():
carrying_object.rpc("set_nm",1)
carrying_object = null
return
- if $"%UseRay".is_colliding():
- var area_c = $"%UseRay".get_collider()
- match area_c.name:
- "SteerArea": #must be a networkedmachine
- if area_c.get_parent().controllable: world.rpc_id(1, "_call_on_server", "_client_request_control_vehicle", {"id" : world.client_id, "machine_path" : area_c.get_parent().get_path(), "char_name" : name})
- "LadderArea":
- mount_ladder(area_c.get_parent())
- "TugArea":
- pass
- "CarryArea":
- if weapon.name == "HANDS" and weapon.can_pickup():
- carrying = true
- carrying_object = area_c.get_parent()
- carrying_object.rpc("set_nm",get_network_master())
- carry_point.global_transform.origin = carrying_object.global_transform.origin
- _:
- pass
+
+ #interact with world
+ if !use_ray.is_colliding(): return
+ var area_c = use_ray.get_collider()
+ match area_c.name:
+ "SteerArea": #must be a networkedmachine
+ if area_c.get_parent().controllable: world.rpc_id(1, "_call_on_server", "_client_request_control_vehicle", {"id" : world.client_id, "machine_path" : area_c.get_parent().get_path(), "char_name" : name})
+ elif !area_c.get_parent().loaded and inventory[area_c.get_parent().ammo_type] > 0:
+ loading = true
+ load_target = area_c.get_parent()
+ load_ammo = area_c.get_parent().ammo_type
+ "LadderArea":
+ mount_ladder(area_c.get_parent())
+ "TugArea":
+ pass
+ "UseArea": #must have method use_generic
+ area_c.get_parent().use_generic(self)
+ "PickupArea": #must be a networkedprojectile. must have inventory_name property
+ var type: String = area_c.get_parent().inventory_name
+ if inventory[type] < inventory_caps[type]:
+ area_c.get_parent().rpc("net_remove")
+ inventory[type] += 1
+ rset("inventory", inventory)
+ "CarryArea":
+ if weapon.name == "HANDS" and weapon.can_pickup():
+ carrying = true
+ carrying_object = area_c.get_parent()
+ carrying_object.rpc("set_nm",get_network_master())
+ carry_point.global_transform.origin = carrying_object.global_transform.origin
+ _:
+ pass
+
+func load_process(delta) -> void:
+ if use_ray.is_colliding() and use_ray.get_collider().get_parent() == load_target and use_held:
+ var progress: float =load_target.increase_load(delta)
+ if progress < 0:
+ if get_network_master() != 1: world.hud.hide_progress()
+ load_target.reset_load()
+ loading = false
+ load_target = null
+ inventory[load_ammo] -= 1
+ else:
+ if get_network_master() != 1: world.hud.set_progress(progress)
+ else:
+ if get_network_master() != 1: world.hud.hide_progress()
+ load_target.reset_load()
+ loading = false
+ load_target = null
func carry_process() -> void:
- if !is_instance_valid(carrying_object):
+ if !is_instance_valid(carrying_object) or carrying_object.get_network_master() != get_network_master():
carrying_object = null
carrying = false
return
@@ -157,6 +208,8 @@ func carry_process() -> void:
# Called every physics tick. 'delta' is constant
func _physics_process(delta: float) -> void:
if is_network_master():
+ if loading: load_process(delta)
+ move_dir_process()
if !is_player: #ai behavior
if ai_should_look: ai_look_at()
if carrying:
@@ -168,6 +221,21 @@ func _physics_process(delta: float) -> void:
else:
walk(delta)
is_on_floor = false #reset whether is on floor in between frames
+
+
+func move_dir_process():
+ direction = Vector3()
+ if is_player:
+ var aim: Basis = head.get_global_transform().basis
+ direction += -move_axis.x * aim.z + move_axis.y * aim.x
+ direction.y = 0
+ direction = direction.normalized()
+ else:
+ if ai_should_pathfind:
+ if !ai_path_process(): return
+ direction = ai_path_target_global - global_transform.origin
+ direction.y = 0
+ direction = direction.normalized()
# called each physics frame
func on_floor_test() -> bool:
@@ -198,19 +266,14 @@ func _integrate_forces(state: PhysicsDirectBodyState) -> void:
break
if i == player_state.get_contact_count() - 1:
friction = 1
- nav.set_velocity(velocity)
+
rpc("set_phys_transform", transform, linear_velocity)
if global_transform.origin.y < -30:
rpc("damage", 500000, "drown", [1, "Davy Jones"], "")
+
+ nav.set_velocity(velocity)
func walk(_delta: float) -> void:
- # Input
- direction = Vector3()
- var aim: Basis = head.get_global_transform().basis
- direction += -move_axis.x * aim.z + move_axis.y * aim.x
- direction.y = 0
- direction = direction.normalized()
-
if floor_normal != Vector3.UP: direction = direction.rotated(floor_normal.cross(Vector3.UP).normalized(), Vector3.UP.angle_to(floor_normal))
# Jump
@@ -306,13 +369,17 @@ remotesync func play_weapon_sound(filepath) -> void:
remotesync func add_rocket_to_scene(pos, dir, id):
var rocket = preload("res://scenes/ballistics/Rocket.tscn").instance()
world.get_node("BALLISTICS").add_child(rocket, true)
- rocket.shooter = name + " (" + world.players_info[get_network_master()][0] + ")"
+ rocket.shooter = name
+ if get_network_master() != 1: rocket.shooter+= " (" + world.players_info[get_network_master()][0] + ")"
rocket.shooter_id = id
rocket.global_transform.origin = pos
rocket.global_transform.basis = Basis(-1*dir.z, dir.y, dir.x)
rocket.add_collision_exception_with(self)
-func set_look_status(target, type="STATIC"):
+func ai_set_state(state: String):
+ ai_state_machine.transition_to(state)
+
+func ai_set_look_status(target, type:String="STATIC"):
if type == "STATIC":
ai_look_target = target
ai_should_look = true
@@ -321,11 +388,9 @@ func set_look_status(target, type="STATIC"):
ai_should_look = true
ai_should_track = true
else:
+ ai_should_look = false
ai_should_track = false
-func set_path_target(target):
- ai_path_target_global = target
-
func ai_look_at():
if ai_should_track:
if is_instance_valid(ai_track_object):
@@ -335,10 +400,33 @@ func ai_look_at():
ai_should_track = false
var p_neck: float = Vector3(ai_look_target.x - neck.global_transform.origin.x, 0, ai_look_target.z - neck.global_transform.origin.z).signed_angle_to(-neck.global_transform.basis.z, neck.global_transform.basis.y )
var p_head: float = Vector3(ai_look_target.x - neck.global_transform.origin.x, ai_look_target.y - head.global_transform.origin.y, ai_look_target.z - neck.global_transform.origin.z).signed_angle_to( -head.global_transform.basis.z, head.global_transform.basis.x)
- if abs(p_neck) > 0.01:
- neck.rotation_degrees.y = lerp(neck.rotation_degrees.y, neck.rotation_degrees.y-p_neck, AI_LOOK_SPEED+abs(p_neck/3.1415))
- if abs(p_head) > 0.01:
- head.rotation_degrees.x = lerp(head.rotation_degrees.x, head.rotation_degrees.x-p_head, AI_LOOK_SPEED+abs(p_head/3.1415))
+ neck.rotation_degrees.y = lerp(neck.rotation_degrees.y, neck.rotation_degrees.y-p_neck, AI_LOOK_SPEED+abs(p_neck/3.1415))
+ head.rotation_degrees.x = lerp(head.rotation_degrees.x, head.rotation_degrees.x-p_head, AI_LOOK_SPEED+abs(p_head/3.1415))
if abs(p_neck) <= 0.01 and abs(p_head) <= 0.01 and !ai_should_track:
ai_should_look = false
+
+func ai_set_path_target(target: Vector3):
+ ai_should_pathfind = true
+ nav.set_target_location(target)
+ #CharacterAIManager.request_find_path(self, target, true)
+
+func ai_set_path_array(arr: PoolVector3Array):
+ world.draw_path(arr)
+ ai_should_pathfind = true
+ ai_path_array = arr
+ ai_path_target_global = ai_path_array[0]
+
+func ai_path_process() -> bool:
+# if (global_transform.origin - ai_path_array[0]).length_squared() < AI_PATH_PROXIM_DIST_SQ:
+# ai_path_array.remove(0)
+# if len(ai_path_array) == 0: #destination reached
+# ai_should_pathfind = false
+# return false
+# else: ai_path_target_global = ai_path_array[0]
+# return true
+ if nav.is_navigation_finished():
+ ai_should_pathfind = false
+ return false
+ ai_path_target_global = nav.get_next_location()
+ return true
diff --git a/godot/scripts/fsm/State.gd b/godot/scripts/fsm/State.gd
new file mode 100644
index 0000000..be7ba2d
--- /dev/null
+++ b/godot/scripts/fsm/State.gd
@@ -0,0 +1,22 @@
+class_name State
+extends Node
+
+var state_machine = null
+
+# Corresponds to the `_process()` callback.
+func update(_delta: float) -> void:
+ pass
+
+# Virtual function. Corresponds to the `_physics_process()` callback.
+func physics_update(_delta: float) -> void:
+ pass
+
+# Virtual function. Called by the state machine upon changing the active state. The `msg` parameter
+# is a dictionary with arbitrary data the state can use to initialize itself.
+func enter(_msg := {}) -> void:
+ pass
+
+# Virtual function. Called by the state machine before changing the active state. Use this function
+# to clean up the state.
+func exit() -> void:
+ pass
diff --git a/godot/scripts/fsm/StateMachine.gd b/godot/scripts/fsm/StateMachine.gd
new file mode 100644
index 0000000..834f036
--- /dev/null
+++ b/godot/scripts/fsm/StateMachine.gd
@@ -0,0 +1,35 @@
+class_name StateMachine
+extends Node
+
+# Emitted when transitioning to a new state.
+signal transitioned(state_name)
+
+# Path to the initial active state. We export it to be able to pick the initial state in the inspector.
+export var initial_state := NodePath()
+
+# The current active state. At the start of the game, we get the `initial_state`.
+onready var state: State = get_node(initial_state)
+
+
+func _ready() -> void:
+ yield(owner, "ready")
+ # The state machine assigns itself to the State objects' state_machine property.
+ for child in get_children():
+ child.state_machine = self
+ state.enter()
+
+func _process(delta: float) -> void:
+ state.update(delta)
+
+func _physics_process(delta: float) -> void:
+ state.physics_update(delta)
+
+func transition_to(target_state_name: String, msg: Dictionary = {}) -> void:
+ if not has_node(target_state_name):
+ print("no state")
+ return
+
+ state.exit()
+ state = get_node(target_state_name)
+ state.enter(msg)
+ emit_signal("transitioned", state.name)
diff --git a/godot/scripts/machines/Cannon.gd b/godot/scripts/machines/Cannon.gd
index 6c0b350..b66903a 100644
--- a/godot/scripts/machines/Cannon.gd
+++ b/godot/scripts/machines/Cannon.gd
@@ -21,6 +21,22 @@ export var max_yaw = 15
onready var muzzle: Spatial = get_node("YawJoint/PitchJoint/Muzzle")
onready var status: Label3D = get_node("StatusNotifier")
+onready var steer_area: Area = get_node("SteerArea")
+
+const ammo_type = "cannonball"
+
+var load_time: float = 3.0
+var load_progress: float = 0.0
+
+func increase_load(delta) -> float:
+ if loaded: return -1.0
+ load_progress += delta
+ if load_progress >= load_time:
+ rpc("load_cannonball")
+ return load_progress/load_time
+
+func reset_load():
+ load_progress = 0
remote func update_aim(pitch_z, yaw_y):
$YawJoint/PitchJoint.rotation_degrees.z = pitch_z
@@ -39,12 +55,13 @@ func mp_init(init_info):
func _ready():
if get_parent().name != "MACHINES": #if cannon is aboard ship
add_collision_exception_with(get_parent().get_parent())
- mode = RigidBody.MODE_KINEMATIC
+ mode = RigidBody.MODE_STATIC
+ print("kinematic")
world_ballistics = world.get_node("BALLISTICS")
if loaded: controllable = true
func on_new_control():
- if is_network_master(): world.cam.attach(self, "STATIC", "./YawJoint/PitchJoint/CameraPoint")
+ if is_network_master() and get_network_master() != 1: world.cam.attach(self, "STATIC", "./YawJoint/PitchJoint/CameraPoint")
func _physics_process(delta):
if in_use and is_network_master(): #aim
@@ -78,9 +95,11 @@ remotesync func fire():
add_collision_exception_with(cball)
cball.global_transform.origin = muzzle.global_transform.origin
cball.linear_velocity = muzzle.global_transform.basis.x*ball_speed
- cball.shooter = user.name + " (" + world.players_info[user.get_network_master()][0] + ")"
+ cball.set_network_master(1)
+ cball.shooter = user.name
+ if user.get_network_master() != 1: cball.shooter += " (" + world.players_info[user.get_network_master()][0] + ")"
cball.shooter_id = user.get_network_master()
- if mode == RigidBody.MODE_KINEMATIC:
+ if mode == RigidBody.MODE_STATIC:
get_parent().get_parent().apply_impulse($YawJoint/PitchJoint.global_transform.origin - get_parent().global_transform.origin, -1*cball.mass*ball_speed*muzzle.global_transform.basis.x)
else:
if is_network_master(): apply_impulse($YawJoint/PitchJoint.global_transform.origin - global_transform.origin, -1*cball.mass*ball_speed*muzzle.global_transform.basis.x)
diff --git a/godot/scripts/vehicles/Gunboat.gd b/godot/scripts/vehicles/Gunboat.gd
index 03252e6..fe5473a 100644
--- a/godot/scripts/vehicles/Gunboat.gd
+++ b/godot/scripts/vehicles/Gunboat.gd
@@ -5,7 +5,7 @@ export var team = 0
const accel = 500000
const turn_accel = 50000
-export(float, 0.0, 1.0) var sail_out = 0.0
+remote var sail_out = 0.0
export var sail_speed : float = 0.2
var sail_turn = 0
export var sail_turn_speed = 30
@@ -87,9 +87,9 @@ func _physics_process(delta):
sail.set_sheet(sail_out)
$Rudder.rotation_degrees.y = rudder_turn
#$Mast.rotation_degrees.y = sail_turn
- #var push_force = accel*sail_out*world.winddir.dot($Mast.global_transform.basis.x)
- #if world.winddir.angle_to($Mast.global_transform.basis.x) < PI/2:
- # add_force(global_transform.basis.x*push_force, Vector3.ZERO)
+ var push_force = accel*sail_out*world.winddir.dot(global_transform.basis.x)
+ if world.winddir.angle_to(global_transform.basis.x) < PI/2:
+ add_force(global_transform.basis.x*push_force, Vector3.ZERO)
add_torque(Vector3(0,-rudder_turn*rudder_constant*(0.5+linear_velocity.dot(global_transform.basis.x)),0))
add_torque(Vector3(-100000*angular_velocity.x,0,0))
add_torque(Vector3(0,0,-100000*angular_velocity.z))
@@ -110,5 +110,5 @@ func _physics_process(delta):
sail_out = clamp(sail_out, 0, 1)
rudder_turn = clamp(rudder_turn, -RUDDER_MAX, RUDDER_MAX)
sail_turn = clamp(sail_turn, -SAIL_MAX, SAIL_MAX)
-
+ rset("sail_out", sail_out)
#add_force(transform.basis.x*accel*Input.get_action_strength("move_forward"), Vector3.ZERO)