211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "rifle.h"
 | 
						|
#include "scene/animation/animation_player.h"
 | 
						|
#include "wave_survival/hitscan_muzzle.h"
 | 
						|
#include "wave_survival/macros.h"
 | 
						|
#include "wave_survival/player_body.h"
 | 
						|
#include "wave_survival/player_input.h"
 | 
						|
#include "wave_survival/weapon_inventory.h"
 | 
						|
 | 
						|
void Rifle::_bind_methods() {
 | 
						|
	BIND_PROPERTY(Variant::FLOAT, ads_factor);
 | 
						|
	BIND_PROPERTY(Variant::FLOAT, recoil_force);
 | 
						|
	BIND_PROPERTY(Variant::FLOAT, recoil_time);
 | 
						|
	ClassDB::bind_method(D_METHOD("reload_full"), &self_type::reload_full);
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::queue_enter_alt() {
 | 
						|
	get_anim()->queue("hip_to_aim");
 | 
						|
	get_anim()->queue("aim");
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::queue_exit_alt() {
 | 
						|
	get_anim()->queue("aim_to_hip");
 | 
						|
	get_anim()->queue("hip");
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::queue_enter_run() {
 | 
						|
	this->running = true;
 | 
						|
	get_anim()->clear_queue();
 | 
						|
	get_anim()->queue("hip_to_run");
 | 
						|
	get_anim()->queue("run");
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::exit_run() {
 | 
						|
	this->running = false;
 | 
						|
	get_anim()->clear_queue();
 | 
						|
	if (this->request_alt_mode) {
 | 
						|
		get_anim()->play("run_to_aim", 0.0);
 | 
						|
		get_anim()->queue("aim");
 | 
						|
	} else {
 | 
						|
		get_anim()->play("run_to_hip", 0.0);
 | 
						|
		get_anim()->queue("hip");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::shoot() {
 | 
						|
	if (!is_animating() && try_use_ammo()) {
 | 
						|
		this->muzzle->shoot();
 | 
						|
		if (this->request_alt_mode) {
 | 
						|
			get_anim()->queue("fire_aim");
 | 
						|
		} else {
 | 
						|
			get_anim()->queue("fire_hip");
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::start_reload_animation() {
 | 
						|
	if (!is_animating() && get_loaded_ammo() < get_max_ammo() && get_inventory()->get_rifle_ammo() > 0) {
 | 
						|
		if (this->in_alt_mode) {
 | 
						|
			get_anim()->queue("aim_to_hip");
 | 
						|
		}
 | 
						|
		get_anim()->queue("reload");
 | 
						|
		get_anim()->queue("hip");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::play_equip_anim() {
 | 
						|
	get_anim()->play("equip", 0.0);
 | 
						|
	get_anim()->queue("hip");
 | 
						|
	get_anim()->advance(0.0);
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::on_primary_fire(bool pressed) {
 | 
						|
	if (pressed) {
 | 
						|
		shoot();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::on_alt_mode(bool alt_mode) {
 | 
						|
	this->request_alt_mode = alt_mode;
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::on_reload() {
 | 
						|
	start_reload_animation();
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::on_animation_changed(String new_animation) {
 | 
						|
	if (new_animation == "aim") {
 | 
						|
		this->in_alt_mode = true;
 | 
						|
		this->fov = this->ads_factor;
 | 
						|
	} else if (new_animation == "hip") {
 | 
						|
		this->in_alt_mode = false;
 | 
						|
		this->fov = 1.0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::ready() {
 | 
						|
	this->muzzle = cast_to<HitscanMuzzle>(get_node(NodePath("%HitscanMuzzle")));
 | 
						|
	get_anim()->connect("current_animation_changed", callable_mp(this, &self_type::on_animation_changed));
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::process(double delta) {
 | 
						|
	String const current{ get_anim()->get_current_animation() };
 | 
						|
	bool run_requested{ this->run_requested() };
 | 
						|
	// track animation progress
 | 
						|
	double const animation_time{ get_anim()->get_current_animation_position() };
 | 
						|
	// animation progress percentually
 | 
						|
	float const progress{ float(CLAMP(animation_time / get_anim()->get_current_animation_length(), 0.0, 1.0)) };
 | 
						|
	if (current == "hip_to_aim" || current == "run_to_aim") { // lerp the current FOV factor depending on the ongoing animation
 | 
						|
		this->fov = Math::lerp(1.f, this->ads_factor, progress);
 | 
						|
	} else if (current == "aim_to_hip") {
 | 
						|
		this->fov = Math::lerp(this->ads_factor, 1.f, progress);
 | 
						|
	} else if (this->request_alt_mode != this->in_alt_mode && !is_animating()) { // act on request flags that have yet to be fulfilled
 | 
						|
		if (this->request_alt_mode) {
 | 
						|
			queue_enter_alt();
 | 
						|
		} else {
 | 
						|
			queue_exit_alt();
 | 
						|
		}
 | 
						|
	} else if (this->running != run_requested) {
 | 
						|
		if (run_requested && !is_animating()) {
 | 
						|
			queue_enter_run();
 | 
						|
		} else if (!run_requested) {
 | 
						|
			exit_run();
 | 
						|
		}
 | 
						|
	} else if (current == "fire_hip" || current == "fire_aim") { // apply fire recoil
 | 
						|
		double t{ animation_time / this->recoil_time };
 | 
						|
		get_camera()->recoil(Math::lerp((double)this->recoil_force, 0.0, CLAMP(t, 0.0, 1.0)) * delta);
 | 
						|
	}
 | 
						|
	if (this->fov != 1.0) {
 | 
						|
		get_camera()->set_fov_factor(this->fov);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::_notification(int what) {
 | 
						|
	if (Engine::get_singleton()->is_editor_hint()) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	switch (what) {
 | 
						|
		default:
 | 
						|
			return;
 | 
						|
		case NOTIFICATION_READY:
 | 
						|
			set_process(true);
 | 
						|
			ready();
 | 
						|
			return;
 | 
						|
		case NOTIFICATION_PROCESS:
 | 
						|
			process(get_process_delta_time());
 | 
						|
			return;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
PackedStringArray Rifle::get_configuration_warnings() const {
 | 
						|
	PackedStringArray warnings{ super_type::get_configuration_warnings() };
 | 
						|
	if (get_node(NodePath("%HitscanMuzzle")) == nullptr) {
 | 
						|
		warnings.push_back("Rifle needs a hitscan muzzle.\nConsider adding a node called '%HitscanMuzzle' of type HitscanMuzzle");
 | 
						|
	}
 | 
						|
	return warnings;
 | 
						|
}
 | 
						|
 | 
						|
bool Rifle::allows_running() const {
 | 
						|
	String const animation{ get_anim()->get_current_animation() };
 | 
						|
	return animation == "run" && !this->request_alt_mode;
 | 
						|
}
 | 
						|
 | 
						|
bool Rifle::run_requested() const {
 | 
						|
	return get_body()->get_wants_to_run() && !this->request_alt_mode;
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::notify_selected() {
 | 
						|
	get_input()->connect(PlayerInput::sig_primary_fire, callable_mp(this, &self_type::on_primary_fire));
 | 
						|
	get_input()->connect(PlayerInput::sig_alt_mode, callable_mp(this, &self_type::on_alt_mode));
 | 
						|
	get_input()->connect(PlayerInput::sig_reload, callable_mp(this, &self_type::on_reload));
 | 
						|
	play_equip_anim();
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::notify_deselected() {
 | 
						|
	get_input()->disconnect(PlayerInput::sig_primary_fire, callable_mp(this, &self_type::on_primary_fire));
 | 
						|
	get_input()->disconnect(PlayerInput::sig_alt_mode, callable_mp(this, &self_type::on_alt_mode));
 | 
						|
	get_input()->disconnect(PlayerInput::sig_reload, callable_mp(this, &self_type::on_reload));
 | 
						|
	this->running = false;
 | 
						|
	this->in_alt_mode = false;
 | 
						|
	this->fov = 1.f;
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::reload_full() {
 | 
						|
	int const available = get_inventory()->withdraw_rifle_ammo(get_max_ammo());
 | 
						|
	reload_num(available);
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::set_ads_factor(float value) {
 | 
						|
	this->ads_factor = value;
 | 
						|
}
 | 
						|
 | 
						|
float Rifle::get_ads_factor() const {
 | 
						|
	return this->ads_factor;
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::set_recoil_force(float value) {
 | 
						|
	this->recoil_force = value;
 | 
						|
}
 | 
						|
 | 
						|
float Rifle::get_recoil_force() const {
 | 
						|
	return this->recoil_force;
 | 
						|
}
 | 
						|
 | 
						|
void Rifle::set_recoil_time(float value) {
 | 
						|
	this->recoil_time = value;
 | 
						|
}
 | 
						|
 | 
						|
float Rifle::get_recoil_time() const {
 | 
						|
	return this->recoil_time;
 | 
						|
}
 |