shooter/weapon/Weapon.cpp

122 lines
5.2 KiB
C++
Raw Normal View History

2021-09-13 15:53:43 +03:00
//
// Created by Иван Ильин on 01.06.2021.
//
#include "Weapon.h"
2021-10-09 13:41:12 +03:00
#include "../engine/ResourceManager.h"
#include "../engine/utils/Log.h"
2021-10-16 20:22:55 +03:00
#include "../ShooterConsts.h"
2021-09-13 15:53:43 +03:00
using namespace std;
2021-10-31 11:39:08 +03:00
Weapon::Weapon(int initialPack, int clipCapacity, double reloadTime, double fireDelay, double damage, double spreading,
std::string fireSound, std::string reloadSound, ObjectNameTag weaponName, const std::string &objFileName,
const Vec3D &s, const Vec3D &t, const Vec3D &r) : RigidBody(std::move(weaponName), objFileName),
_initialPack(initialPack), _clipCapacity(clipCapacity),
_reloadTime(reloadTime), _fireDelay(fireDelay),
_damage(damage), _spreading(spreading),
_fireSound(std::move(fireSound)),
_reloadSound(std::move(reloadSound)) {
2021-10-28 16:58:02 +03:00
_stockAmmo = _initialPack - _clipCapacity;
_clipAmmo = _clipCapacity;
2021-10-02 20:36:07 +03:00
2021-10-28 16:58:02 +03:00
loadObj(objFileName, s);
2021-10-02 20:36:07 +03:00
setCollider(false);
rotate(r);
translate(t);
2021-09-13 15:53:43 +03:00
}
2021-10-31 11:39:08 +03:00
FireInformation Weapon::fire(std::function<IntersectionInformation(const Vec3D &, const Vec3D &)> rayCastFunction,
const Vec3D &position, const Vec3D &direction) {
if (_clipAmmo == 0) {
2021-09-13 15:53:43 +03:00
reload();
2021-10-31 18:09:28 +03:00
if (_clipAmmo == 0 && SoundController::getStatus(SoundTag("noAmmo")) != sf::Sound::Status::Playing) {
2022-02-23 17:29:42 +03:00
SoundController::loadAndPlay(SoundTag("noAmmo"), ShooterConsts::NO_AMMO_SOUND);
2021-10-28 16:58:02 +03:00
}
2021-09-13 15:53:43 +03:00
}
2021-10-31 11:39:08 +03:00
if (_clipAmmo <= 0 || std::abs(Time::time() - _lastFireTime) < _fireDelay ||
std::abs(Time::time() - _lastReloadTime) < _reloadTime) {
2021-10-22 19:42:32 +03:00
return FireInformation{std::map<ObjectNameTag, double>(), false};
2021-10-28 16:58:02 +03:00
}
2021-09-13 15:53:43 +03:00
_lastFireTime = Time::time();
_clipAmmo--;
2022-02-23 17:29:42 +03:00
SoundController::loadAndPlay(SoundTag("fireSound_" + name().str()), _fireSound);
2021-09-13 15:53:43 +03:00
Log::log("Weapon::fire (" + std::to_string(_stockAmmo) + " : " + std::to_string(_clipAmmo) + ")");
2022-07-07 13:14:00 +03:00
if (_fireCallBack != nullptr) {
_fireCallBack();
}
2021-10-22 19:42:32 +03:00
return FireInformation{processFire(std::move(rayCastFunction), position, direction), true};
2021-09-13 15:53:43 +03:00
}
void Weapon::reload() {
2022-07-07 13:14:00 +03:00
if (_stockAmmo == 0 || std::abs(Time::time() - _lastReloadTime) < _reloadTime || _clipAmmo == _clipCapacity) {
2021-09-13 15:53:43 +03:00
return;
2021-10-28 16:58:02 +03:00
}
2021-10-31 11:39:08 +03:00
if (_clipCapacity - _clipAmmo <= _stockAmmo) {
2021-09-13 15:53:43 +03:00
_stockAmmo -= _clipCapacity - _clipAmmo;
_clipAmmo = _clipCapacity;
} else {
_clipAmmo += _stockAmmo;
_stockAmmo = 0;
}
2022-02-23 17:29:42 +03:00
SoundController::loadAndPlay(SoundTag("reloadSound_" + name().str()), _reloadSound);
2021-09-13 15:53:43 +03:00
Log::log("Weapon::reload (" + std::to_string(_stockAmmo) + " : " + std::to_string(_clipAmmo) + ")");
_lastReloadTime = Time::time();
2021-11-01 17:08:36 +03:00
if (_reloadCallBack != nullptr) {
2021-11-01 17:08:36 +03:00
_reloadCallBack();
}
2021-09-13 15:53:43 +03:00
}
2021-10-31 11:39:08 +03:00
std::map<ObjectNameTag, double>
Weapon::processFire(std::function<IntersectionInformation(const Vec3D &, const Vec3D &)> rayCastFunction,
2021-11-09 22:54:20 +03:00
const Vec3D &position, const Vec3D &direction) const {
// Standard weapon usually fire one bullet at a time
// But some types of weapon can fire several bullet at the same time (for ex. shotgun)
// That's why processFire() is s virtual function
return fireABullet(std::move(rayCastFunction), position, direction);
2021-10-16 20:22:55 +03:00
}
2021-10-31 11:39:08 +03:00
std::map<ObjectNameTag, double>
2021-11-09 22:54:20 +03:00
Weapon::fireABullet(std::function<IntersectionInformation(const Vec3D &, const Vec3D &)> rayCastFunction,
const Vec3D &cameraPosition, const Vec3D &direction) const {
2021-10-17 10:21:10 +03:00
std::map<ObjectNameTag, double> damagedPlayers;
2021-09-13 15:53:43 +03:00
2021-11-09 22:54:20 +03:00
double spreading = _spreading * ShooterConsts::FIRE_DISTANCE / 100.0;
2021-10-16 20:22:55 +03:00
2021-09-13 15:53:43 +03:00
//generate random vector
2021-11-09 22:54:20 +03:00
Vec3D randV(spreading * (1.0 - 2.0 * static_cast<double>(rand()) / RAND_MAX),
spreading * (1.0 - 2.0 * static_cast<double>(rand()) / RAND_MAX),
spreading * (1.0 - 2.0 * static_cast<double>(rand()) / RAND_MAX));
2021-09-13 15:53:43 +03:00
// damage player
2021-11-09 22:54:20 +03:00
auto rayCast = rayCastFunction(cameraPosition, cameraPosition + direction * ShooterConsts::FIRE_DISTANCE + randV);
if (rayCast.objectName.contains(ObjectNameTag("Enemy"))) {
2021-10-28 16:58:02 +03:00
damagedPlayers[rayCast.objectName] += _damage / (1.0 + rayCast.distanceToObject);
// If you hit the head the damage will be doubled
2021-11-09 22:54:20 +03:00
if (rayCast.objectName.contains(ObjectNameTag("_head"))) {
damagedPlayers[rayCast.objectName] += _damage / (1.0 + rayCast.distanceToObject);
}
// If you hit the foot the damage will be divided by 2
2021-11-09 22:54:20 +03:00
if (rayCast.objectName.contains(ObjectNameTag("_foot_"))) {
damagedPlayers[rayCast.objectName] -= 0.5 * _damage / (1.0 + rayCast.distanceToObject);
}
2021-10-28 16:58:02 +03:00
}
2021-09-13 15:53:43 +03:00
// add trace line
2021-10-31 11:39:08 +03:00
Vec3D lineFrom = position() + model() * Vec3D(triangles().back()[0]);
Vec3D lineTo = rayCast.intersected ? rayCast.pointOfIntersection : position() +
2021-11-09 22:54:20 +03:00
direction * ShooterConsts::FIRE_DISTANCE +
randV;
_addTraceCallBack(lineFrom, lineTo);
2021-09-13 15:53:43 +03:00
return damagedPlayers;
2021-11-09 22:54:20 +03:00
}