diff --git a/rwengine/src/ai/CharacterController.cpp b/rwengine/src/ai/CharacterController.cpp index df45cfc0..5b775ca6 100644 --- a/rwengine/src/ai/CharacterController.cpp +++ b/rwengine/src/ai/CharacterController.cpp @@ -700,7 +700,7 @@ bool Activities::UseItem::update(CharacterObject *character, auto currentTime = animator->getAnimationTime(AnimIndexAction); if (currentTime >= fireTime && !fired) { - /// @todo weapon hit here + Weapon::meleeHit(weapon, character); fired = true; } diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 2a2a5134..654ac79f 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -23,6 +23,8 @@ #include "ai/PlayerController.hpp" #include "ai/TrafficDirector.hpp" +#include "dynamics/HitTest.hpp" + #include "data/CutsceneData.hpp" #include "data/InstanceData.hpp" @@ -566,12 +568,22 @@ void GameWorld::destroyEffect(VisualFX& effect) { } void GameWorld::doWeaponScan(const WeaponScan& scan) { - RW_CHECK(scan.type != WeaponScan::RADIUS, - "Radius scans not implemented yet"); - if (scan.type == WeaponScan::RADIUS) { - // TODO - // Requires custom ConvexResultCallback + HitTest test {*dynamicsWorld}; + const auto result = test.sphereTest(scan.center, scan.radius); + + for(const auto& target : result) { + if (!scan.doesDamage(target.object)) { + continue; + } + + GameObject::DamageInfo di; + di.damageSource = scan.center; + di.type = GameObject::DamageInfo::Melee; + di.hitpoints = scan.damage; + target.object->takeDamage(di); + } + } else if (scan.type == WeaponScan::HITSCAN) { btVector3 from(scan.center.x, scan.center.y, scan.center.z), to(scan.end.x, scan.end.y, scan.end.z); diff --git a/rwengine/src/items/Weapon.cpp b/rwengine/src/items/Weapon.cpp index de9b383a..fd3464fd 100644 --- a/rwengine/src/items/Weapon.cpp +++ b/rwengine/src/items/Weapon.cpp @@ -22,7 +22,7 @@ void Weapon::fireHitscan(WeaponData* weapon, CharacterObject* owner) { auto fireOrigin = glm::vec3(handMatrix[3]); float dmg = static_cast(weapon->damage); - owner->engine->doWeaponScan({dmg, fireOrigin, rayend, weapon}); + owner->engine->doWeaponScan({dmg, fireOrigin, rayend, weapon, owner}); } void Weapon::fireProjectile(WeaponData* weapon, CharacterObject* owner, @@ -49,3 +49,14 @@ void Weapon::fireProjectile(WeaponData* weapon, CharacterObject* owner, pool.insert(std::move(projectile)); owner->engine->allObjects.push_back(ptr); } + +void Weapon::meleeHit(WeaponData* weapon, CharacterObject* character) { + const auto center = character->getPosition() + character->getRotation() + * weapon->fireOffset; + auto e = character->engine; + e->doWeaponScan({ + static_cast(weapon->damage), + center, weapon->meleeRadius, weapon, + character + }); +} diff --git a/rwengine/src/items/Weapon.hpp b/rwengine/src/items/Weapon.hpp index 14c1e8aa..dd601355 100644 --- a/rwengine/src/items/Weapon.hpp +++ b/rwengine/src/items/Weapon.hpp @@ -57,6 +57,7 @@ struct WeaponScan { namespace Weapon { void fireProjectile(WeaponData* weapon, CharacterObject* character, float force); void fireHitscan(WeaponData *weapon, CharacterObject* character); +void meleeHit(WeaponData *weapon, CharacterObject* character); } #endif diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index 83022832..f9ada284 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -164,7 +164,7 @@ public: } struct DamageInfo { - enum DamageType { Explosion, Burning, Bullet, Physics }; + enum DamageType { Explosion, Burning, Bullet, Physics, Melee }; /** * World position of damage