summaryrefslogtreecommitdiff
path: root/src/player_controller/playercontroller.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/player_controller/playercontroller.cpp')
-rw-r--r--src/player_controller/playercontroller.cpp325
1 files changed, 325 insertions, 0 deletions
diff --git a/src/player_controller/playercontroller.cpp b/src/player_controller/playercontroller.cpp
new file mode 100644
index 0000000..6ea5544
--- /dev/null
+++ b/src/player_controller/playercontroller.cpp
@@ -0,0 +1,325 @@
+#include "playercontroller.h"
+#include <ResourceLoader.hpp>
+#include <PackedScene.hpp>
+#include <Input.hpp>
+
+using namespace godot;
+
+PlayerController::PlayerController () { }
+PlayerController::~PlayerController () { }
+
+void PlayerController::_register_methods() {
+ register_method("_ready", &PlayerController::_ready);
+ register_method("get_init_info", &PlayerController::get_init_info);
+ register_method("mp_init", &PlayerController::mp_init);
+ register_method("set_phys_transform", &PlayerController::set_phys_transform, GODOT_METHOD_RPC_MODE_REMOTE);
+ register_method("_process", &PlayerController::_process);
+ register_method("initiate_use", &PlayerController::initiate_use);
+ register_method("set_net_owner", &PlayerController::set_net_owner, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+ register_method("deselect_character", &PlayerController::deselect_character);
+ register_method("take_control_of_machine", &PlayerController::take_control_of_machine);
+ register_method("lose_machine", &PlayerController::lose_machine);
+ register_method("_physics_process", &PlayerController::_physics_process);
+ register_method("on_floor_test", &PlayerController::on_floor_test);
+ register_method("_integrate_forces", &PlayerController::_integrate_forces);
+ register_method("walk", &PlayerController::walk);
+ register_method("jump", &PlayerController::jump);
+ register_method("swim", &PlayerController::swim);
+ register_method("enter_water", &PlayerController::enter_water);
+ register_method("exit_water", &PlayerController::exit_water);
+ register_method("mount_ladder", &PlayerController::mount_ladder);
+ register_method("climb_ladder", &PlayerController::climb_ladder);
+ register_method("leave_ladder", &PlayerController::leave_ladder);
+ register_method("damage", &PlayerController::damage, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+ register_method("remove_dead_character", &PlayerController::remove_dead_character, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+ register_method("net_apply_impulse", &PlayerController::net_apply_impulse, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+
+ register_property<PlayerController, String>("team", &PlayerController::team, String("RED"));
+ register_property<PlayerController, int>("health", &PlayerController::health, int(100));
+ register_property<PlayerController, float>("mouse_sensitivity", &PlayerController::mouse_sensitivity, float(12.0));
+ register_property<PlayerController, float>("FOV", &PlayerController::FOV, float(90.0));
+ register_property<PlayerController, float>("jump_height", &PlayerController::jump_height, float(300.0));
+ register_property<PlayerController, bool>("is_player", &PlayerController::is_player, bool(false));
+ register_property<PlayerController, float>("walk_speed", &PlayerController::walk_speed, float(5.0));
+}
+
+void PlayerController::_init() {
+ weapon = nullptr;
+ world = nullptr;
+ mouse_axis = Vector2::ZERO;
+ velocity = Vector3::ZERO;
+ direction = Vector3::ZERO;
+ move_axis = Vector2::ZERO;
+ floorspeed = Vector3::ZERO;
+ jumping = false;
+ can_jump = true;
+ FLOOR_MAX_ANGLE = Math::deg2rad(46.0);
+ in_water = false;
+ swim_speed = 450.0;
+ climb_speed = 5.0;
+ controlling_machine = false;
+ machine = nullptr;
+ ladder_m = nullptr;
+ player_state = nullptr;
+ is_on_floor = false;
+ floor_normal = Vector3::UP;
+ acceleration = 80.0;
+ c_friction = 4.0;
+ air_control = 0.3;
+}
+
+void PlayerController::_ready() {
+ head = get_node<Spatial>(NodePath("Neck/Head"));
+ neck = get_node<Spatial>(NodePath("Neck"));
+ useray = get_node<RayCast>(NodePath("Neck/Head/UseRay"));
+ nametag = get_node<Label3D>(NodePath("Nametag"));
+ nav = get_node<NavigationAgent>(NodePath("NavigationAgent"));
+ Ref<PackedScene> p = ResourceLoader::get_singleton()->load("res://scenes/weapons/w_Rockets.tscn");
+ weapon = (Node *)p->instance();
+ add_child(weapon);
+ world = get_tree()->get_root()->get_node<Spatial>("GAMEWORLD");
+ cam = (PlayerCam *)world->call("get_cam");
+}
+
+Dictionary PlayerController::get_init_info() {
+ return Dictionary::make("linear_velocity", get_linear_velocity(), "angular_velocity", get_angular_velocity(), "controlling_machine", controlling_machine, "team", team, "health", health, "nametag", get_node<Label3D>("Nametag")->get_text());
+}
+
+void PlayerController::mp_init(Dictionary init_info) {
+ for(int i = 0; i < init_info.keys().size(); i++)
+ set(init_info.keys()[i], init_info[init_info.keys()[i]]);
+ nametag->set_text(init_info["nametag"]);
+}
+
+void PlayerController::set_phys_transform(Transform trfrm, Vector3 lvel) {
+ set_transform(trfrm);
+ set_linear_velocity(lvel);
+}
+
+void PlayerController::_process(float _delta) {
+ const Input *input_singleton = Input::get_singleton();
+ if(is_player && !world->call("is_chatting_f")){
+ if(input_singleton->is_action_just_pressed("use"))
+ initiate_use();
+ if(controlling_machine) {
+ if(input_singleton->is_action_just_pressed("fire"))machine->call("attack1");
+ if(input_singleton->is_action_just_pressed("fire2"))machine->call("attack2");
+ }
+ }
+}
+
+void PlayerController::initiate_use() {
+ if(controlling_machine){machine->call("relinquish_control"); return; }
+ if(ladder_m != nullptr) { leave_ladder(); return; }
+ if(useray->is_colliding()){
+ const Node *area_c = (Node *) useray->get_collider();
+ if(area_c->get_name() == "SteerArea")
+ world->rpc_id(1, "_call_on_server", "_client_request_control_vehicle", Dictionary::make("id", world->call("get_client_id"), "machine_path", area_c->get_parent()->get_path(), "char_name", get_name()));
+ else if(area_c->get_name() == "LadderArea")
+ mount_ladder((Spatial *)area_c->get_parent());
+ else if(area_c->get_name() == "TugArea")return;
+ else if(area_c->get_name() == "PickupArea")return;
+ }
+}
+
+void PlayerController::set_net_owner(int owner_id) {
+ nametag->set_text("");
+ set_network_master(owner_id);
+ if(owner_id != 1)
+ nametag->set_text(String(world->call("get_players_info")[owner_id][0]));
+ if(get_tree()->get_network_unique_id() != 1){
+ if(owner_id == (int)world->call("get_client_id")){
+ nametag->set_visible(false);
+ world->call("set_player_char", this);
+ is_player = true;
+ cam->attach(this, "FIRSTPERSON", "./Neck/Head");
+ }else{
+ nametag->set_visible(true);
+ is_player = false;
+ }
+ world->get_node("HUD")->call("update_characters");
+ }
+}
+
+void PlayerController::deselect_character() {
+ if(is_network_master()){
+ world->call("set_player_char", nullptr);
+ if((int)world->call("get_client_id") != 1)cam->attach(world, "STATIC", "./DEFAULTCAM");
+ rpc("set_net_owner", 1);
+ }
+}
+
+void PlayerController::take_control_of_machine(RigidBody *slave_machine) {
+ machine = slave_machine;
+ controlling_machine = true;
+}
+
+void PlayerController::lose_machine() {
+ if(is_network_master())cam->attach(this, "FIRSTPERSON", "./Neck/Head");
+ controlling_machine = false;
+ machine = nullptr;
+}
+
+void PlayerController::_physics_process(float delta) {
+ if(is_network_master()) {
+ if (ladder_m != nullptr)
+ climb_ladder(delta);
+ else if( !on_floor_test() && in_water)
+ swim(delta);
+ else
+ walk(delta);
+ is_on_floor = false;// #reset whether is on floor in between frames
+ }
+}
+
+bool PlayerController::on_floor_test() {
+ const RayCast *feet = get_node<RayCast>("Feet");
+ if(feet->is_colliding()){
+ is_on_floor = true;
+ floor_normal = Vector3::UP;
+ floorspeed = feet->get_collider()->has_method("get_linear_velocity") ? feet->get_collider()->get_linear_velocity() : Vector3::ZERO;
+ return true;
+ }
+ if(player_state){
+ for(int i = 0;i< player_state->get_contact_count()) {
+ float contact_angle_from_up = Vector3::UP.angle_to(player_state->get_contact_local_normal(i))
+ if(contact_angle_from_up < FLOOR_MAX_ANGLE) {
+ floor_normal = player_state->get_contact_local_normal(i);
+ is_on_floor = true;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void PlayerController::_integrate_forces(PhysicsDirectBodyState *state) {
+ if(!is_network_master()) return;
+ player_state = state;
+ velocity = state->get_linear_velocity();
+ for(int i=0; i < player_state->get_contact_count(); i++) {
+ float contact_angle_from_up = Vector3::UP.angle_to(player_state->get_contact_local_normal(i));
+ if(contact_angle_from_up > FLOOR_MAX_ANGLE && !is_on_floor){
+ set_friction(0);
+ break;
+ }
+ if(i == player_state.get_contact_count() - 1)
+ set_friction(1);
+ }
+ rpc("set_phys_transform", get_transform(), get_linear_velocity());
+ if(get_global_transform().origin.y < -30)
+ rpc("damage", 500000, "drown", Array::make(1, String("Davy Jones"));
+}
+
+void PlayerController::walk(float _delta) {
+// # 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
+// if is_player and jumping and is_on_floor and can_jump:
+// jump()
+//
+// #max walk speed
+// var _speed = walk_speed
+// var _temp_accel: float = acceleration
+// var _cspeed = sqrt(pow(velocity.x-floorspeed.x,2)+pow(velocity.z-floorspeed.z,2))
+//
+// if not is_on_floor:
+// _temp_accel *= air_control
+}
+
+void PlayerController::jump() {
+ can_jump = false;
+ apply_central_impulse(Vector3.UP*jump_height);
+ yield(get_tree().create_timer(0.05),"timeout");
+ can_jump = true;
+}
+
+void PlayerController::swim(float _delta) {
+// #drag and buoyancy
+ add_central_force(Vector3::UP*weight);
+ add_central_force(-100*linear_velocity);
+// #controls
+ Basis dir = head->get_global_transform().basis;
+ Vector3 m_dir = -move_axis.x * dir.z + move_axis.y * dir.x;
+ m_dir = m_dir.normalized();
+ add_central_force(swim_speed*m_dir);
+ if(jumping) add_central_force(Vector3::UP*get_weight()*0.5);
+}
+
+void PlayerController::enter_water() {
+ in_water = true;
+}
+
+void PlayerController::exit_water() {
+ in_water = false;
+}
+
+void PlayerController::mount_ladder(Spatial *target_ladder) {
+ Spatial *ladder_tracker = Spatial::new();
+ ladder_tracker->name = get_name();
+ target_ladder->add_child(ladder_tracker);
+ ladder_tracker->set_transform(target_ladder->get_node<Spatial>("BOTTOM")->get_transform();
+
+ ladder_tracker->set_global_transform( Transform(target_ladder->call("get_nearest_point_to_route", get_global_transform().origin), ladder_tracker->get_global_transform().basis ) );
+ look_at(get_global_transform().origin + target_ladder->get_global_transform().basis.x, target_ladder->get_global_transform().basis.y)
+
+ ladder_m = ladder_tracker;
+ Transform t = ladder_m->get_global_transform();
+ set_global_transform( Transform(t.origin, t.basis.orthonormalized()));
+ set_linear_velocity(Vector3::ZERO);
+ set_gravity_scale(0.0);
+}
+
+void PlayerController::climb_ladder(float delta) {
+ Vector3 new_ladder_pos = ladder_m->get_global_transform().origin + ladder_m->get_global_transform().basis.y.normalized() * move_axis.x * delta * climb_speed;
+ float prog = ladder_m->get_parent()->call("get_climb_scalar", new_ladder_pos)
+ if(prog >= 0.0 and && <= 1.0)
+ ladder_m->set_global_transform(Transform(new_ladder_pos, ladder_m->get_global_transform().basis));
+ Transform t = ladder_m->get_global_transform();
+ set_global_transform( Transform(t.origin, t.basis.orthonormalized()));
+}
+
+void PlayerController::leave_ladder() {
+ if((ladder_m->get_parent()->get_node<Spatial>("TOP")->global_transform.origin - get_global_transform().origin).length_squared() < 0.01)
+ apply_central_impulse(-400*ladder_m->get_global_transform().basis.z);
+ Transform t = get_global_transform();
+ t.basis = world->get_global_transform().basis;
+ set_global_transform(t);
+ set_gravity_scale(1.0);
+ ladder_m->queue_free();
+ ladder_m = nullptr;
+}
+
+void PlayerController::damage(int dmg_amt, String _type, Array shooter, String extra = ".") {
+ health -= dmg_amt;
+ int shooter_id = shooter[0];
+ String shooter_text = shooter[1];
+ if(health <= 0 && is_network_master()){
+ if(shooter_id != get_network_master() && shooter_id != 1) world->rpc_id(shooter_id, "game_killsound");
+ if(get_network_master() == 1)
+ world->call("_call_on_server", "_character_death", Dictionary::make("killer_id", shooter_id, "killer", shooter_text, "victim_mp_id", get_network_master(), "victim", get_name(), "extra", extra));
+ else
+ world->rpc_id(1, "_call_on_server", "_character_death", Dictionary::make("killer_id", shooter_id, "killer", shooter_text, "victim_mp_id", get_network_master(), "victim", get_name(), "extra", extra));
+ } else if( is_network_master())
+ if(shooter_id != get_network_master() && shooter_id != 1) world->rpc_id(shooter_id, "game_hitsound");
+}
+
+void PlayerController::remove_dead_character() {
+ if(is_network_master() && machine != nullptr)
+ machine->call("relinquish_control");
+ deselect_character();
+ queue_free();
+}
+
+void PlayerController::net_apply_impulse(Vector3 impulse_v) {
+ apply_central_impulse(impulse_v);
+}
+
+