mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 15:02:34 +02:00
Remove InventoryItem and WeaponItem
They served no purpose other than to awkwardly implement weapon firing This is now handled in the Weapon::fire* functions, and everything else has been changed to reference weapon data or inventory indices directly
This commit is contained in:
parent
44f73af9e9
commit
5c78930c1b
@ -58,9 +58,8 @@ set(RWENGINE_SOURCES
|
|||||||
src/engine/SaveGame.hpp
|
src/engine/SaveGame.hpp
|
||||||
src/engine/ScreenText.cpp
|
src/engine/ScreenText.cpp
|
||||||
src/engine/ScreenText.hpp
|
src/engine/ScreenText.hpp
|
||||||
src/items/InventoryItem.hpp
|
src/items/Weapon.cpp
|
||||||
src/items/WeaponItem.cpp
|
src/items/Weapon.hpp
|
||||||
src/items/WeaponItem.hpp
|
|
||||||
src/loaders/DataLoader.cpp
|
src/loaders/DataLoader.cpp
|
||||||
src/loaders/DataLoader.hpp
|
src/loaders/DataLoader.hpp
|
||||||
src/loaders/GenericDATLoader.cpp
|
src/loaders/GenericDATLoader.cpp
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#include <btBulletDynamicsCommon.h>
|
#include <btBulletDynamicsCommon.h>
|
||||||
#include <ai/CharacterController.hpp>
|
#include <ai/CharacterController.hpp>
|
||||||
#include <objects/CharacterObject.hpp>
|
|
||||||
#include <objects/VehicleObject.hpp>
|
|
||||||
|
|
||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
#include <engine/Animator.hpp>
|
#include <engine/Animator.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
#include <engine/GameData.hpp>
|
||||||
|
#include <engine/GameWorld.hpp>
|
||||||
|
#include <items/Weapon.hpp>
|
||||||
|
#include <objects/CharacterObject.hpp>
|
||||||
|
#include <objects/VehicleObject.hpp>
|
||||||
#include <rw/defines.hpp>
|
#include <rw/defines.hpp>
|
||||||
|
|
||||||
constexpr float kCloseDoorIdleTime = 2.f;
|
constexpr float kCloseDoorIdleTime = 2.f;
|
||||||
@ -384,14 +385,20 @@ bool Activities::ExitVehicle::update(CharacterObject *character,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <data/Model.hpp>
|
bool Activities::UseItem::update(CharacterObject *character,
|
||||||
#include <engine/GameData.hpp>
|
CharacterController *controller) {
|
||||||
#include <engine/GameWorld.hpp>
|
|
||||||
bool Activities::ShootWeapon::update(CharacterObject *character,
|
|
||||||
CharacterController *controller) {
|
|
||||||
RW_UNUSED(controller);
|
RW_UNUSED(controller);
|
||||||
|
|
||||||
auto &wepdata = _item->getWeaponData();
|
if (itemslot >= kMaxInventorySlots) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto world = character->engine;
|
||||||
|
const auto &weapon = world->data->weaponData.at(itemslot);
|
||||||
|
auto &state = character->getCurrentState().weapons[itemslot];
|
||||||
|
auto animator = character->animator;
|
||||||
|
auto shootanim = world->data->animations[weapon->animation1];
|
||||||
|
auto throwanim = world->data->animations[weapon->animation2];
|
||||||
|
|
||||||
// Instant hit weapons loop their anim
|
// Instant hit weapons loop their anim
|
||||||
// Thrown projectiles have lob / throw.
|
// Thrown projectiles have lob / throw.
|
||||||
@ -400,85 +407,73 @@ bool Activities::ShootWeapon::update(CharacterObject *character,
|
|||||||
character->setRotation(
|
character->setRotation(
|
||||||
glm::angleAxis(character->getLook().x, glm::vec3{0.f, 0.f, 1.f}));
|
glm::angleAxis(character->getLook().x, glm::vec3{0.f, 0.f, 1.f}));
|
||||||
|
|
||||||
RW_CHECK(wepdata->inventorySlot < maxInventorySlots,
|
if (state.bulletsClip == 0 && state.bulletsTotal > 0) {
|
||||||
"Inventory slot out of bounds");
|
state.bulletsClip +=
|
||||||
auto &itemState =
|
std::min(int(state.bulletsTotal), weapon->clipSize);
|
||||||
character->getCurrentState().weapons[wepdata->inventorySlot];
|
state.bulletsTotal -= state.bulletsClip;
|
||||||
if (itemState.bulletsClip == 0 && itemState.bulletsTotal > 0) {
|
|
||||||
itemState.bulletsClip +=
|
|
||||||
std::min(int(itemState.bulletsTotal), wepdata->clipSize);
|
|
||||||
itemState.bulletsTotal -= itemState.bulletsClip;
|
|
||||||
}
|
}
|
||||||
bool hasammo = itemState.bulletsClip > 0;
|
bool hasammo = state.bulletsClip > 0;
|
||||||
|
|
||||||
if (wepdata->fireType == WeaponData::INSTANT_HIT) {
|
if (weapon->fireType == WeaponData::INSTANT_HIT) {
|
||||||
if (_item->isFiring(character) && hasammo) {
|
if (!character->getCurrentState().primaryActive) {
|
||||||
auto shootanim =
|
// Character is no longer firing
|
||||||
character->engine->data->animations[wepdata->animation1];
|
return true;
|
||||||
if (shootanim) {
|
}
|
||||||
if (character->animator->getAnimation(AnimIndexAction) !=
|
if (hasammo && shootanim) {
|
||||||
shootanim) {
|
if (animator->getAnimation(AnimIndexAction) != shootanim) {
|
||||||
character->playActivityAnimation(shootanim, false, false);
|
character->playActivityAnimation(shootanim, false, false);
|
||||||
}
|
|
||||||
|
|
||||||
auto loopstart = wepdata->animLoopStart / 100.f;
|
|
||||||
auto loopend = wepdata->animLoopEnd / 100.f;
|
|
||||||
auto firetime = wepdata->animFirePoint / 100.f;
|
|
||||||
|
|
||||||
auto currID =
|
|
||||||
character->animator->getAnimationTime(AnimIndexAction);
|
|
||||||
|
|
||||||
if (currID >= firetime && !_fired) {
|
|
||||||
itemState.bulletsClip--;
|
|
||||||
_item->fire(character);
|
|
||||||
_fired = true;
|
|
||||||
}
|
|
||||||
if (currID > loopend) {
|
|
||||||
character->animator->setAnimationTime(AnimIndexAction,
|
|
||||||
loopstart);
|
|
||||||
_fired = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (character->animator->isCompleted(AnimIndexAction)) {
|
auto loopstart = weapon->animLoopStart / 100.f;
|
||||||
return true;
|
auto loopend = weapon->animLoopEnd / 100.f;
|
||||||
|
auto firetime = weapon->animFirePoint / 100.f;
|
||||||
|
|
||||||
|
auto currenttime = animator->getAnimationTime(AnimIndexAction);
|
||||||
|
|
||||||
|
if (currenttime >= firetime && !fired) {
|
||||||
|
state.bulletsClip--;
|
||||||
|
Weapon::fireHitscan(weapon.get(), character);
|
||||||
|
fired = true;
|
||||||
}
|
}
|
||||||
|
if (currenttime > loopend) {
|
||||||
|
animator->setAnimationTime(AnimIndexAction, loopstart);
|
||||||
|
fired = false;
|
||||||
|
}
|
||||||
|
} else if (animator->isCompleted(AnimIndexAction)) {
|
||||||
|
// Should we exit this state when out of ammo?
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// @todo Use Thrown flag instead of project (RPG isn't thrown eg.)
|
/// @todo Use Thrown flag instead of project (RPG isn't thrown eg.)
|
||||||
else if (wepdata->fireType == WeaponData::PROJECTILE && hasammo) {
|
else if (weapon->fireType == WeaponData::PROJECTILE && hasammo) {
|
||||||
auto shootanim =
|
if (animator->getAnimation(AnimIndexAction) == shootanim) {
|
||||||
character->engine->data->animations[wepdata->animation1];
|
if (character->getCurrentState().primaryActive) {
|
||||||
auto throwanim =
|
power = animator->getAnimationTime(AnimIndexAction) / 0.5f;
|
||||||
character->engine->data->animations[wepdata->animation2];
|
}
|
||||||
|
if (animator->isCompleted(AnimIndexAction)) {
|
||||||
if (character->animator->getAnimation(AnimIndexAction) == shootanim) {
|
|
||||||
if (character->animator->isCompleted(AnimIndexAction)) {
|
|
||||||
character->playActivityAnimation(throwanim, false, false);
|
character->playActivityAnimation(throwanim, false, false);
|
||||||
}
|
}
|
||||||
} else if (character->animator->getAnimation(AnimIndexAction) ==
|
} else if (animator->getAnimation(AnimIndexAction) == throwanim) {
|
||||||
throwanim) {
|
auto firetime = weapon->animCrouchFirePoint / 100.f;
|
||||||
auto firetime = wepdata->animCrouchFirePoint / 100.f;
|
auto currID = animator->getAnimationTime(AnimIndexAction);
|
||||||
auto currID =
|
|
||||||
character->animator->getAnimationTime(AnimIndexAction);
|
|
||||||
|
|
||||||
if (currID >= firetime && !_fired) {
|
if (currID >= firetime && !fired) {
|
||||||
itemState.bulletsClip--;
|
state.bulletsClip--;
|
||||||
_item->fire(character);
|
Weapon::fireProjectile(weapon.get(), character, power);
|
||||||
_fired = true;
|
fired = true;
|
||||||
}
|
}
|
||||||
if (character->animator->isCompleted(AnimIndexAction)) {
|
if (animator->isCompleted(AnimIndexAction)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
character->playActivityAnimation(throwanim, false, true);
|
character->playActivityAnimation(shootanim, false, true);
|
||||||
}
|
}
|
||||||
} else if (wepdata->fireType == WeaponData::MELEE) {
|
} else if (weapon->fireType == WeaponData::MELEE) {
|
||||||
RW_CHECK(wepdata->fireType != WeaponData::MELEE,
|
RW_CHECK(weapon->fireType != WeaponData::MELEE,
|
||||||
"Melee attacks not implemented");
|
"Melee attacks not implemented");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
RW_ERROR("Unrecognized fireType: " << wepdata->fireType);
|
RW_ERROR("Unrecognized fireType: " << weapon->fireType);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor this with an ugly macro to reduce code dup.
|
// TODO: Refactor this with an ugly macro to reduce code dup.
|
||||||
class WeaponItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Activities for CharacterController behaviour
|
* @brief Activities for CharacterController behaviour
|
||||||
@ -217,13 +216,14 @@ struct ExitVehicle : public CharacterController::Activity {
|
|||||||
bool update(CharacterObject* character, CharacterController* controller);
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShootWeapon : public CharacterController::Activity {
|
struct UseItem : public CharacterController::Activity {
|
||||||
DECL_ACTIVITY(ShootWeapon)
|
DECL_ACTIVITY(UseItem)
|
||||||
|
|
||||||
WeaponItem* _item;
|
int itemslot;
|
||||||
bool _fired;
|
bool fired = false;
|
||||||
|
float power = 0.f;
|
||||||
|
|
||||||
ShootWeapon(WeaponItem* item) : _item(item), _fired(false) {
|
UseItem(int slot) : itemslot(slot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(CharacterObject* character, CharacterController* controller);
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <ai/TrafficDirector.hpp>
|
#include <ai/TrafficDirector.hpp>
|
||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <job/WorkContext.hpp>
|
#include <job/WorkContext.hpp>
|
||||||
#include <loaders/LoaderIDE.hpp>
|
#include <loaders/LoaderIDE.hpp>
|
||||||
#include <loaders/LoaderIPL.hpp>
|
#include <loaders/LoaderIPL.hpp>
|
||||||
@ -99,11 +98,6 @@ GameWorld::GameWorld(Logger* log, WorkContext* work, GameData* dat)
|
|||||||
new btGhostPairCallback());
|
new btGhostPairCallback());
|
||||||
gContactProcessedCallback = ContactProcessedCallback;
|
gContactProcessedCallback = ContactProcessedCallback;
|
||||||
dynamicsWorld->setInternalTickCallback(PhysicsTickCallback, this);
|
dynamicsWorld->setInternalTickCallback(PhysicsTickCallback, this);
|
||||||
|
|
||||||
// Populate inventory items
|
|
||||||
for (auto& w : data->weaponData) {
|
|
||||||
inventoryItems.push_back(new WeaponItem(inventoryItems.size(), w));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameWorld::~GameWorld() {
|
GameWorld::~GameWorld() {
|
||||||
@ -433,14 +427,13 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
|||||||
PickupObject* pickup = nullptr;
|
PickupObject* pickup = nullptr;
|
||||||
auto pickuptype = (PickupObject::PickupType)type;
|
auto pickuptype = (PickupObject::PickupType)type;
|
||||||
|
|
||||||
// Attempt to find an InventoryItem associated with this model
|
|
||||||
auto it = std::find_if(
|
auto it = std::find_if(
|
||||||
inventoryItems.begin(), inventoryItems.end(),
|
data->weaponData.begin(), data->weaponData.end(),
|
||||||
[=](InventoryItem* itm) { return itm->getModelID() == id; });
|
[=](const std::shared_ptr<WeaponData>& x) { return x->modelID == id; });
|
||||||
|
|
||||||
// If nothing, create a generic pickup instead of an item pickup
|
// If nothing, create a generic pickup instead of an item pickup
|
||||||
if (it != inventoryItems.end()) {
|
if (it != data->weaponData.end()) {
|
||||||
pickup = new ItemPickup(this, pos, modelInfo, pickuptype, *it);
|
pickup = new ItemPickup(this, pos, modelInfo, pickuptype, it->get());
|
||||||
} else {
|
} else {
|
||||||
RW_UNIMPLEMENTED("Non-weapon pickups");
|
RW_UNIMPLEMENTED("Non-weapon pickups");
|
||||||
pickup = new PickupObject(this, pos, modelInfo, pickuptype);
|
pickup = new PickupObject(this, pos, modelInfo, pickuptype);
|
||||||
@ -640,14 +633,6 @@ float GameWorld::getGameTime() const {
|
|||||||
return state->gameTime;
|
return state->gameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryItem* GameWorld::getInventoryItem(uint16_t weaponId) const {
|
|
||||||
RW_CHECK(weaponId < inventoryItems.size(), "InventoryItem ID out of range");
|
|
||||||
if (weaponId >= inventoryItems.size()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return inventoryItems[weaponId];
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleVehicleResponse(GameObject* object, btManifoldPoint& mp, bool isA) {
|
void handleVehicleResponse(GameObject* object, btManifoldPoint& mp, bool isA) {
|
||||||
bool isVehicle = object->type() == GameObject::Vehicle;
|
bool isVehicle = object->type() == GameObject::Vehicle;
|
||||||
if (!isVehicle) return;
|
if (!isVehicle) return;
|
||||||
|
@ -27,7 +27,6 @@ class ViewCamera;
|
|||||||
#include <render/VisualFX.hpp>
|
#include <render/VisualFX.hpp>
|
||||||
|
|
||||||
struct BlipData;
|
struct BlipData;
|
||||||
class InventoryItem;
|
|
||||||
struct WeaponScan;
|
struct WeaponScan;
|
||||||
struct VehicleGenerator;
|
struct VehicleGenerator;
|
||||||
|
|
||||||
@ -179,13 +178,6 @@ public:
|
|||||||
|
|
||||||
float getGameTime() const;
|
float getGameTime() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief getInventoryItem
|
|
||||||
* @param weaponId The Weapon ID (inventory slot) of the weapon to fetch
|
|
||||||
* @return Instance of the weapon
|
|
||||||
*/
|
|
||||||
InventoryItem* getInventoryItem(uint16_t weaponId) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game data
|
* Game data
|
||||||
*/
|
*/
|
||||||
@ -353,11 +345,6 @@ private:
|
|||||||
|
|
||||||
std::vector<AreaIndicatorInfo> areaIndicators;
|
std::vector<AreaIndicatorInfo> areaIndicators;
|
||||||
|
|
||||||
/**
|
|
||||||
* Inventory Item instances
|
|
||||||
*/
|
|
||||||
std::vector<InventoryItem*> inventoryItems;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag for pausing the simulation
|
* Flag for pausing the simulation
|
||||||
*/
|
*/
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <engine/SaveGame.hpp>
|
#include <engine/SaveGame.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/GameObject.hpp>
|
#include <objects/GameObject.hpp>
|
||||||
#include <objects/InstanceObject.hpp>
|
#include <objects/InstanceObject.hpp>
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _INVENTORYITEM_HPP_
|
|
||||||
#define _INVENTORYITEM_HPP_
|
|
||||||
|
|
||||||
class GameObject;
|
|
||||||
class CharacterObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The InventoryItem class
|
|
||||||
*
|
|
||||||
* Instanciated once per item type
|
|
||||||
*/
|
|
||||||
class InventoryItem {
|
|
||||||
int _itemID;
|
|
||||||
int _inventorySlot;
|
|
||||||
int _modelID;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
InventoryItem(int itemID, int invSlot, int model)
|
|
||||||
: _itemID(itemID), _inventorySlot(invSlot), _modelID(model) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~InventoryItem() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief getObject
|
|
||||||
* @return The ID of the model associated with the item.
|
|
||||||
*/
|
|
||||||
int getModelID() {
|
|
||||||
return _modelID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief getItemID
|
|
||||||
* @return The index of this item in the item list
|
|
||||||
*/
|
|
||||||
int getItemID() {
|
|
||||||
return _itemID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief getInventorySlot
|
|
||||||
* @return The inventory slot number for this item
|
|
||||||
*/
|
|
||||||
int getInventorySlot() const {
|
|
||||||
return _inventorySlot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief primary Implements mouse 1 action
|
|
||||||
* @param owner The character using this item
|
|
||||||
*/
|
|
||||||
virtual void primary(CharacterObject* owner) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see primary
|
|
||||||
* @param owner The character using this item
|
|
||||||
*/
|
|
||||||
virtual void secondary(CharacterObject* owner) = 0;
|
|
||||||
|
|
||||||
constexpr static int NO_INVSLOT = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
48
rwengine/src/items/Weapon.cpp
Normal file
48
rwengine/src/items/Weapon.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <data/Skeleton.hpp>
|
||||||
|
#include <engine/GameWorld.hpp>
|
||||||
|
#include <items/Weapon.hpp>
|
||||||
|
#include <objects/ProjectileObject.hpp>
|
||||||
|
|
||||||
|
void Weapon::fireHitscan(WeaponData* weapon, CharacterObject* owner) {
|
||||||
|
auto handFrame = owner->getModel()->findFrame("srhand");
|
||||||
|
glm::mat4 handMatrix;
|
||||||
|
if (handFrame) {
|
||||||
|
while (handFrame->getParent()) {
|
||||||
|
handMatrix =
|
||||||
|
owner->skeleton->getMatrix(handFrame->getIndex()) * handMatrix;
|
||||||
|
handFrame = handFrame->getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto farTarget =
|
||||||
|
owner->getPosition() +
|
||||||
|
owner->getRotation() * glm::vec3(0.f, weapon->hitRange, 0.f);
|
||||||
|
auto handPos = glm::vec3(handMatrix * glm::vec4(0.f, 0.f, 0.f, 1.f));
|
||||||
|
auto fireOrigin = owner->getPosition() + owner->getRotation() * handPos;
|
||||||
|
|
||||||
|
owner->engine->doWeaponScan(
|
||||||
|
WeaponScan(weapon->damage, fireOrigin, farTarget, weapon));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Weapon::fireProjectile(WeaponData* weapon, CharacterObject* owner,
|
||||||
|
float force) {
|
||||||
|
auto handPos = glm::vec3(0.f, 1.5f, 1.f);
|
||||||
|
auto fireOrigin = owner->getPosition() + owner->getRotation() * handPos;
|
||||||
|
auto direction =
|
||||||
|
owner->getRotation() * glm::normalize(glm::vec3{0.f, 1.f, 1.f});
|
||||||
|
|
||||||
|
auto pt = weapon->name == "grenade" ? ProjectileObject::Grenade
|
||||||
|
: ProjectileObject::Molotov;
|
||||||
|
|
||||||
|
force = std::max(0.1f, force);
|
||||||
|
|
||||||
|
auto projectile = new ProjectileObject(
|
||||||
|
owner->engine, fireOrigin,
|
||||||
|
{pt, direction,
|
||||||
|
17.f * force, /// @todo pull a better velocity from somewhere
|
||||||
|
3.5f, weapon});
|
||||||
|
|
||||||
|
auto& pool = owner->engine->getTypeObjectPool(projectile);
|
||||||
|
pool.insert(projectile);
|
||||||
|
owner->engine->allObjects.push_back(projectile);
|
||||||
|
}
|
12
rwengine/src/items/Weapon.hpp
Normal file
12
rwengine/src/items/Weapon.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef RWENGINE_WEAPON_HPP
|
||||||
|
#define RWENGINE_WEAPON_HPP
|
||||||
|
|
||||||
|
#include <data/WeaponData.hpp>
|
||||||
|
#include <objects/CharacterObject.hpp>
|
||||||
|
|
||||||
|
namespace Weapon {
|
||||||
|
void fireProjectile(WeaponData* wepon, CharacterObject* character, float force);
|
||||||
|
void fireHitscan(WeaponData* wepon, CharacterObject* character);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,160 +0,0 @@
|
|||||||
#include <ai/CharacterController.hpp>
|
|
||||||
#include <data/Model.hpp>
|
|
||||||
#include <data/Skeleton.hpp>
|
|
||||||
#include <engine/Animator.hpp>
|
|
||||||
#include <engine/GameData.hpp>
|
|
||||||
#include <engine/GameWorld.hpp>
|
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
|
||||||
#include <objects/ProjectileObject.hpp>
|
|
||||||
|
|
||||||
void WeaponItem::fireHitscan(CharacterObject* owner) {
|
|
||||||
auto handFrame = owner->getModel()->findFrame("srhand");
|
|
||||||
glm::mat4 handMatrix;
|
|
||||||
if (handFrame) {
|
|
||||||
while (handFrame->getParent()) {
|
|
||||||
handMatrix =
|
|
||||||
owner->skeleton->getMatrix(handFrame->getIndex()) * handMatrix;
|
|
||||||
handFrame = handFrame->getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto farTarget =
|
|
||||||
owner->getPosition() +
|
|
||||||
owner->getRotation() * glm::vec3(0.f, _wepData->hitRange, 0.f);
|
|
||||||
auto handPos = glm::vec3(handMatrix * glm::vec4(0.f, 0.f, 0.f, 1.f));
|
|
||||||
auto fireOrigin = owner->getPosition() + owner->getRotation() * handPos;
|
|
||||||
|
|
||||||
owner->engine->doWeaponScan(
|
|
||||||
WeaponScan(_wepData->damage, fireOrigin, farTarget, _wepData.get()));
|
|
||||||
|
|
||||||
// Particle FX involved:
|
|
||||||
// - smokeII emited around barrel
|
|
||||||
// - Some circle particle used for the tracer
|
|
||||||
// - smoke emited at hit point
|
|
||||||
// - gunflash
|
|
||||||
#if 0 // Should be merged into the VisualFX system
|
|
||||||
auto flashDir = owner->getRotation() * glm::vec3{0.f, 0.f, 1.f};
|
|
||||||
auto flashUp = owner->getRotation() * glm::vec3{0.f, -1.f, 0.f};
|
|
||||||
|
|
||||||
auto tracerTex = owner->engine->data->findTexture("shad_exp")->getName();
|
|
||||||
auto flashTex = owner->engine->data->findTexture("gunflash2")->getName();
|
|
||||||
auto flashTex1 = owner->engine->data->findTexture("gunflash1")->getName();
|
|
||||||
|
|
||||||
float tracertime = 0.1f;
|
|
||||||
auto distance = glm::distance(fireOrigin, farTarget);
|
|
||||||
const float tracerspeed = distance / tracertime * 0.5f;
|
|
||||||
float tracersize = _wepData->hitRange / 4.f;
|
|
||||||
float flashtime = 0.015f;
|
|
||||||
auto shotdir = glm::normalize(farTarget - fireOrigin);
|
|
||||||
|
|
||||||
/// @TODO move this into rendering logic.
|
|
||||||
/*_character->engine->renderer.addParticle({
|
|
||||||
fireOrigin + shotdir * tracersize / 2.f,
|
|
||||||
shotdir,
|
|
||||||
tracerspeed,
|
|
||||||
GameRenderer::FXParticle::UpCamera,
|
|
||||||
_character->engine->gameTime, tracertime,
|
|
||||||
tracerTex,
|
|
||||||
{0.04f, tracersize},
|
|
||||||
{0.f, 0.f, 0.f}
|
|
||||||
});
|
|
||||||
|
|
||||||
_character->engine->renderer.addParticle({
|
|
||||||
fireOrigin,
|
|
||||||
flashDir,
|
|
||||||
0.f,
|
|
||||||
GameRenderer::FXParticle::Free,
|
|
||||||
_character->engine->gameTime, flashtime,
|
|
||||||
flashTex,
|
|
||||||
{0.2f, 0.2f},
|
|
||||||
flashUp
|
|
||||||
});
|
|
||||||
|
|
||||||
_character->engine->renderer.addParticle({
|
|
||||||
fireOrigin + shotdir * 0.1f,
|
|
||||||
flashDir,
|
|
||||||
0.f,
|
|
||||||
GameRenderer::FXParticle::Free,
|
|
||||||
_character->engine->gameTime, flashtime,
|
|
||||||
flashTex,
|
|
||||||
{0.2f, 0.2f},
|
|
||||||
flashUp
|
|
||||||
});
|
|
||||||
|
|
||||||
_character->engine->renderer.addParticle({
|
|
||||||
fireOrigin + shotdir * 0.2f,
|
|
||||||
flashDir,
|
|
||||||
0.f,
|
|
||||||
GameRenderer::FXParticle::Free,
|
|
||||||
_character->engine->gameTime, flashtime,
|
|
||||||
flashTex1,
|
|
||||||
{0.2f, 0.2f},
|
|
||||||
flashUp
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeaponItem::fireProjectile(CharacterObject* owner) {
|
|
||||||
auto handPos = glm::vec3(0.f, 1.5f, 1.f);
|
|
||||||
auto fireOrigin = owner->getPosition() + owner->getRotation() * handPos;
|
|
||||||
auto direction =
|
|
||||||
owner->getRotation() * glm::normalize(glm::vec3{0.f, 1.f, 1.f});
|
|
||||||
|
|
||||||
auto pt = _wepData->name == "grenade" ? ProjectileObject::Grenade
|
|
||||||
: ProjectileObject::Molotov;
|
|
||||||
|
|
||||||
// Work out the velocity multiplier as a function of how long the player
|
|
||||||
// Was holding down the fire button. If _fireStop < 0.f then the player
|
|
||||||
// is still holding the button down.
|
|
||||||
float throwTime = owner->engine->getGameTime() -
|
|
||||||
owner->getCurrentState().primaryStartTime / 1000.f;
|
|
||||||
float forceFactor = throwTime;
|
|
||||||
if (owner->getCurrentState().primaryEndTime >=
|
|
||||||
owner->getCurrentState().primaryStartTime) {
|
|
||||||
uint32_t heldTime = owner->getCurrentState().primaryEndTime -
|
|
||||||
owner->getCurrentState().primaryStartTime;
|
|
||||||
forceFactor = (heldTime) / 1000.f;
|
|
||||||
}
|
|
||||||
forceFactor = std::max(0.1f, forceFactor / throwTime);
|
|
||||||
|
|
||||||
auto projectile = new ProjectileObject(
|
|
||||||
owner->engine, fireOrigin,
|
|
||||||
{pt, direction,
|
|
||||||
17.f * forceFactor, /// @todo pull a better velocity from somewhere
|
|
||||||
3.5f, _wepData});
|
|
||||||
|
|
||||||
auto& pool = owner->engine->getTypeObjectPool(projectile);
|
|
||||||
pool.insert(projectile);
|
|
||||||
owner->engine->allObjects.push_back(projectile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeaponItem::primary(CharacterObject* owner) {
|
|
||||||
if (owner->getCurrentState().primaryActive) {
|
|
||||||
// ShootWeapon will call ::fire() on us at the appropriate time.
|
|
||||||
owner->controller->setNextActivity(new Activities::ShootWeapon(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeaponItem::secondary(CharacterObject* owner) {
|
|
||||||
RW_UNUSED(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeaponItem::fire(CharacterObject* owner) {
|
|
||||||
switch (_wepData->fireType) {
|
|
||||||
case WeaponData::INSTANT_HIT:
|
|
||||||
fireHitscan(owner);
|
|
||||||
break;
|
|
||||||
case WeaponData::PROJECTILE:
|
|
||||||
fireProjectile(owner);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/// @todo meele
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WeaponItem::isFiring(CharacterObject* owner) {
|
|
||||||
return owner->getCurrentState().primaryActive;
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _WEAPONITEM_HPP_
|
|
||||||
#define _WEAPONITEM_HPP_
|
|
||||||
#include <data/WeaponData.hpp>
|
|
||||||
#include <items/InventoryItem.hpp>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The WeaponItem class
|
|
||||||
* Logic for basic weapon types
|
|
||||||
*
|
|
||||||
* This is instanciated once -per item type-, so state is shared between
|
|
||||||
* all instances of the same weapon. Timing is controlled by the CharacterState
|
|
||||||
*/
|
|
||||||
class WeaponItem : public InventoryItem {
|
|
||||||
std::shared_ptr<WeaponData> _wepData;
|
|
||||||
|
|
||||||
void fireHitscan(CharacterObject* owner);
|
|
||||||
void fireProjectile(CharacterObject* owner);
|
|
||||||
|
|
||||||
public:
|
|
||||||
WeaponItem(int itemID, std::shared_ptr<WeaponData> data)
|
|
||||||
: InventoryItem(itemID, data->inventorySlot, data->modelID)
|
|
||||||
, _wepData(data) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void primary(CharacterObject* owner);
|
|
||||||
|
|
||||||
void secondary(CharacterObject* owner);
|
|
||||||
|
|
||||||
void fire(CharacterObject* owner);
|
|
||||||
|
|
||||||
bool isFiring(CharacterObject* owner);
|
|
||||||
|
|
||||||
std::shared_ptr<WeaponData>& getWeaponData() {
|
|
||||||
return _wepData;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -3,7 +3,6 @@
|
|||||||
#include <engine/Animator.hpp>
|
#include <engine/Animator.hpp>
|
||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <items/InventoryItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
#include <rw/defines.hpp>
|
#include <rw/defines.hpp>
|
||||||
@ -14,8 +13,7 @@ static glm::vec3 enter_offset(0.81756252f, 0.34800607f, -0.486281008f);
|
|||||||
const float CharacterObject::DefaultJumpSpeed = 2.f;
|
const float CharacterObject::DefaultJumpSpeed = 2.f;
|
||||||
|
|
||||||
CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot,
|
const glm::quat& rot, BaseModelInfo* modelinfo)
|
||||||
BaseModelInfo *modelinfo)
|
|
||||||
: GameObject(engine, pos, rot, modelinfo)
|
: GameObject(engine, pos, rot, modelinfo)
|
||||||
, currentState({})
|
, currentState({})
|
||||||
, currentVehicle(nullptr)
|
, currentVehicle(nullptr)
|
||||||
@ -521,12 +519,11 @@ void CharacterObject::activityFinished() {
|
|||||||
motionBlockedByActivity = false;
|
motionBlockedByActivity = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterObject::addToInventory(InventoryItem* item) {
|
void CharacterObject::addToInventory(int slot, int ammo) {
|
||||||
RW_CHECK(item->getInventorySlot() < maxInventorySlots,
|
RW_CHECK(slot < kMaxInventorySlots, "Slot greater than kMaxInventorySlots");
|
||||||
"Inventory Slot greater than maxInventorySlots");
|
if (slot < kMaxInventorySlots) {
|
||||||
if (item->getInventorySlot() < maxInventorySlots) {
|
currentState.weapons[slot].weaponId = slot;
|
||||||
currentState.weapons[item->getInventorySlot()].weaponId =
|
currentState.weapons[slot].bulletsTotal += ammo;
|
||||||
item->getItemID();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,19 +531,16 @@ void CharacterObject::setActiveItem(int slot) {
|
|||||||
currentState.currentWeapon = slot;
|
currentState.currentWeapon = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryItem* CharacterObject::getActiveItem() {
|
|
||||||
if (currentVehicle) return nullptr;
|
|
||||||
auto weaponId = currentState.weapons[currentState.currentWeapon].weaponId;
|
|
||||||
return engine->getInventoryItem(weaponId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CharacterObject::removeFromInventory(int slot) {
|
void CharacterObject::removeFromInventory(int slot) {
|
||||||
currentState.weapons[slot].weaponId = 0;
|
currentState.weapons[slot].weaponId = 0;
|
||||||
|
if (currentState.currentWeapon == slot) {
|
||||||
|
currentState.currentWeapon = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterObject::cycleInventory(bool up) {
|
void CharacterObject::cycleInventory(bool up) {
|
||||||
if (up) {
|
if (up) {
|
||||||
for (int j = currentState.currentWeapon + 1; j < maxInventorySlots;
|
for (int j = currentState.currentWeapon + 1; j < kMaxInventorySlots;
|
||||||
++j) {
|
++j) {
|
||||||
if (currentState.weapons[j].weaponId != 0) {
|
if (currentState.weapons[j].weaponId != 0) {
|
||||||
currentState.currentWeapon = j;
|
currentState.currentWeapon = j;
|
||||||
@ -565,7 +559,7 @@ void CharacterObject::cycleInventory(bool up) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Nothing? set the highest
|
// Nothing? set the highest
|
||||||
for (int j = maxInventorySlots - 1; j >= 0; --j) {
|
for (int j = kMaxInventorySlots - 1; j >= 0; --j) {
|
||||||
if (currentState.weapons[j].weaponId != 0 || j == 0) {
|
if (currentState.weapons[j].weaponId != 0 || j == 0) {
|
||||||
currentState.currentWeapon = j;
|
currentState.currentWeapon = j;
|
||||||
return;
|
return;
|
||||||
@ -575,17 +569,21 @@ void CharacterObject::cycleInventory(bool up) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CharacterObject::useItem(bool active, bool primary) {
|
void CharacterObject::useItem(bool active, bool primary) {
|
||||||
if (getActiveItem()) {
|
/// @todo verify if this is the correct logic
|
||||||
|
auto item = getActiveItem();
|
||||||
|
if (currentState.weapons[item].weaponId == unsigned(item)) {
|
||||||
if (primary) {
|
if (primary) {
|
||||||
if (active)
|
if (!currentState.primaryActive && active) {
|
||||||
currentState.primaryStartTime = engine->getGameTime() * 1000.f;
|
// If we've just started, activate
|
||||||
else
|
controller->setNextActivity(new Activities::UseItem(item));
|
||||||
currentState.primaryEndTime = engine->getGameTime() * 1000.f;
|
}
|
||||||
|
else if (currentState.primaryActive && !active) {
|
||||||
|
// UseItem will cancel itself upon !primaryActive
|
||||||
|
}
|
||||||
currentState.primaryActive = active;
|
currentState.primaryActive = active;
|
||||||
getActiveItem()->primary(this);
|
|
||||||
} else {
|
} else {
|
||||||
currentState.secondaryActive = active;
|
currentState.secondaryActive = active;
|
||||||
getActiveItem()->secondary(this);
|
/// @todo handle scopes and sights
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <objects/GameObject.hpp>
|
#include <objects/GameObject.hpp>
|
||||||
|
|
||||||
constexpr int maxInventorySlots = 13;
|
constexpr int kMaxInventorySlots = 13;
|
||||||
|
|
||||||
// Animation slots used for character animation blending
|
// Animation slots used for character animation blending
|
||||||
constexpr unsigned int AnimIndexMovement = 0;
|
constexpr unsigned int AnimIndexMovement = 0;
|
||||||
@ -26,18 +26,15 @@ struct CharacterState {
|
|||||||
float rotation;
|
float rotation;
|
||||||
float health = 100.f;
|
float health = 100.f;
|
||||||
float armour = 0.f;
|
float armour = 0.f;
|
||||||
std::array<CharacterWeaponSlot, maxInventorySlots> weapons;
|
std::array<CharacterWeaponSlot, kMaxInventorySlots> weapons;
|
||||||
uint16_t currentWeapon = 0;
|
uint16_t currentWeapon = 0;
|
||||||
uint32_t lastFireTimeMS = 0;
|
uint32_t lastFireTimeMS = 0;
|
||||||
bool primaryActive = false;
|
bool primaryActive = false;
|
||||||
bool secondaryActive = false;
|
bool secondaryActive = false;
|
||||||
uint32_t primaryStartTime = 0;
|
|
||||||
uint32_t primaryEndTime = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VehicleObject;
|
class VehicleObject;
|
||||||
class GameWorld;
|
class GameWorld;
|
||||||
class InventoryItem;
|
|
||||||
|
|
||||||
struct AnimationGroup {
|
struct AnimationGroup {
|
||||||
Animation* idle;
|
Animation* idle;
|
||||||
@ -234,9 +231,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
void activityFinished();
|
void activityFinished();
|
||||||
|
|
||||||
void addToInventory(InventoryItem* item);
|
/**
|
||||||
|
* @brief addToInventory Adds ammo to the specified item slot
|
||||||
|
* @param slot The slot to add ammo for
|
||||||
|
* @param ammo The quanity of ammunition to add
|
||||||
|
*
|
||||||
|
* Will give the weapon (set the ID) if it is not possessed
|
||||||
|
*/
|
||||||
|
void addToInventory(int slot, int ammo);
|
||||||
|
|
||||||
void setActiveItem(int slot);
|
void setActiveItem(int slot);
|
||||||
InventoryItem* getActiveItem();
|
int getActiveItem() const { return currentState.currentWeapon; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief removeFromInventory Removes item at slot from inventory
|
||||||
|
*/
|
||||||
void removeFromInventory(int slot);
|
void removeFromInventory(int slot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
|
#include <data/WeaponData.hpp>
|
||||||
|
#include <engine/GameData.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/ItemPickup.hpp>
|
#include <objects/ItemPickup.hpp>
|
||||||
#include <rw/defines.hpp>
|
#include <rw/defines.hpp>
|
||||||
|
|
||||||
ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position,
|
ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position,
|
||||||
BaseModelInfo *modelinfo, PickupType type,
|
BaseModelInfo *modelinfo, PickupType type,
|
||||||
InventoryItem *item)
|
WeaponData *item)
|
||||||
: PickupObject(world, position, modelinfo, type), item(item) {
|
: PickupObject(world, position, modelinfo, type), item(item) {
|
||||||
RW_CHECK(item != nullptr, "Pickup created with null item");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ItemPickup::onCharacterTouch(CharacterObject *character) {
|
bool ItemPickup::onCharacterTouch(CharacterObject *character) {
|
||||||
character->addToInventory(item);
|
auto totalRounds = 0;
|
||||||
auto &wep = character->getCurrentState().weapons[item->getInventorySlot()];
|
|
||||||
auto totalRounds = 0, clipRounds = 0;
|
|
||||||
|
|
||||||
switch (item->getModelID()) {
|
switch (item->modelID) {
|
||||||
case 173: /* Pistol */
|
case 173: /* Pistol */
|
||||||
totalRounds = 45;
|
totalRounds = 45;
|
||||||
break;
|
break;
|
||||||
@ -50,8 +48,7 @@ bool ItemPickup::onCharacterTouch(CharacterObject *character) {
|
|||||||
totalRounds /= 5;
|
totalRounds /= 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
wep.bulletsTotal = totalRounds;
|
character->addToInventory(item->inventorySlot, totalRounds);
|
||||||
wep.bulletsClip = clipRounds;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef _ITEMPICKUP_HPP_
|
#ifndef _ITEMPICKUP_HPP_
|
||||||
#define _ITEMPICKUP_HPP_
|
#define _ITEMPICKUP_HPP_
|
||||||
|
#include <data/WeaponData.hpp>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <objects/PickupObject.hpp>
|
#include <objects/PickupObject.hpp>
|
||||||
|
|
||||||
class InventoryItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ItemPickup class
|
* @brief The ItemPickup class
|
||||||
* Inserts an item into a characters inventory on pickup.
|
* Inserts an item into a characters inventory on pickup.
|
||||||
*/
|
*/
|
||||||
class ItemPickup : public PickupObject {
|
class ItemPickup : public PickupObject {
|
||||||
InventoryItem* item;
|
WeaponData* item;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ItemPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo, PickupType type,
|
ItemPickup(GameWorld* world, const glm::vec3& position,
|
||||||
InventoryItem* item);
|
BaseModelInfo* modelinfo, PickupType type, WeaponData* item);
|
||||||
|
|
||||||
bool onCharacterTouch(CharacterObject* character);
|
bool onCharacterTouch(CharacterObject* character);
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
/** Time to dentonation or removal */
|
/** Time to dentonation or removal */
|
||||||
float time;
|
float time;
|
||||||
|
|
||||||
std::shared_ptr<WeaponData> weapon;
|
WeaponData* weapon;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include <ai/CharacterController.hpp>
|
#include <ai/CharacterController.hpp>
|
||||||
#include <data/ModelData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include <items/InventoryItem.hpp>
|
|
||||||
|
|
||||||
#include <data/CutsceneData.hpp>
|
#include <data/CutsceneData.hpp>
|
||||||
#include <data/Skeleton.hpp>
|
#include <data/Skeleton.hpp>
|
||||||
|
@ -32,7 +32,6 @@ class ProjectileObject;
|
|||||||
class CutsceneObject;
|
class CutsceneObject;
|
||||||
|
|
||||||
class Animator;
|
class Animator;
|
||||||
class InventoryItem;
|
|
||||||
|
|
||||||
class Renderer;
|
class Renderer;
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <render/ObjectRenderer.hpp>
|
#include <render/ObjectRenderer.hpp>
|
||||||
|
|
||||||
// Objects that we know how to turn into renderlist entries
|
// Objects that we know how to turn into renderlist entries
|
||||||
#include <items/InventoryItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/CutsceneObject.hpp>
|
#include <objects/CutsceneObject.hpp>
|
||||||
#include <objects/InstanceObject.hpp>
|
#include <objects/InstanceObject.hpp>
|
||||||
@ -302,31 +301,30 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian,
|
|||||||
renderFrame(pedestrian->getModel(), root->getChildren()[0], matrixModel,
|
renderFrame(pedestrian->getModel(), root->getChildren()[0], matrixModel,
|
||||||
pedestrian, 1.f, outList);
|
pedestrian, 1.f, outList);
|
||||||
|
|
||||||
if (pedestrian->getActiveItem()) {
|
auto item = pedestrian->getActiveItem();
|
||||||
auto item = pedestrian->getActiveItem();
|
const auto& weapon = pedestrian->engine->data->weaponData[item];
|
||||||
|
|
||||||
if (item->getModelID() == -1) {
|
if (weapon->modelID == -1) {
|
||||||
return; // No model for this item
|
return; // No model for this item
|
||||||
}
|
|
||||||
|
|
||||||
auto handFrame = pedestrian->getModel()->findFrame("srhand");
|
|
||||||
glm::mat4 localMatrix;
|
|
||||||
if (handFrame) {
|
|
||||||
while (handFrame->getParent()) {
|
|
||||||
localMatrix =
|
|
||||||
pedestrian->skeleton->getMatrix(handFrame->getIndex()) *
|
|
||||||
localMatrix;
|
|
||||||
handFrame = handFrame->getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume items are all simple
|
|
||||||
auto simple =
|
|
||||||
m_world->data->findModelInfo<SimpleModelInfo>(item->getModelID());
|
|
||||||
auto geometry = simple->getAtomic(0)->getGeometries().at(0);
|
|
||||||
renderGeometry(simple->getModel(), geometry, matrixModel * localMatrix,
|
|
||||||
1.f, nullptr, outList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto handFrame = pedestrian->getModel()->findFrame("srhand");
|
||||||
|
glm::mat4 localMatrix;
|
||||||
|
if (handFrame) {
|
||||||
|
while (handFrame->getParent()) {
|
||||||
|
localMatrix =
|
||||||
|
pedestrian->skeleton->getMatrix(handFrame->getIndex()) *
|
||||||
|
localMatrix;
|
||||||
|
handFrame = handFrame->getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume items are all simple
|
||||||
|
auto simple =
|
||||||
|
m_world->data->findModelInfo<SimpleModelInfo>(weapon->modelID);
|
||||||
|
auto geometry = simple->getAtomic(0)->getGeometries().at(0);
|
||||||
|
renderGeometry(simple->getModel(), geometry, matrixModel * localMatrix, 1.f,
|
||||||
|
nullptr, outList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectRenderer::renderVehicle(VehicleObject* vehicle,
|
void ObjectRenderer::renderVehicle(VehicleObject* vehicle,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "DrawUI.hpp"
|
#include "DrawUI.hpp"
|
||||||
#include <ai/PlayerController.hpp>
|
#include <ai/PlayerController.hpp>
|
||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
|
#include <data/WeaponData.hpp>
|
||||||
#include <render/GameRenderer.hpp>
|
#include <render/GameRenderer.hpp>
|
||||||
|
|
||||||
#include <glm/gtc/constants.hpp>
|
#include <glm/gtc/constants.hpp>
|
||||||
@ -152,16 +152,14 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
|
|||||||
render->text.renderText(ti);
|
render->text.renderText(ti);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
InventoryItem* current = player->getCharacter()->getActiveItem();
|
auto item = player->getCharacter()->getActiveItem();
|
||||||
|
auto weapon = world->data->weaponData[item];
|
||||||
std::string itemTextureName = "fist";
|
std::string itemTextureName = "fist";
|
||||||
if (current) {
|
if (weapon && weapon->modelID > 0) {
|
||||||
uint16_t model = current->getModelID();
|
auto model =
|
||||||
if (model > 0) {
|
world->data->findModelInfo<SimpleModelInfo>(weapon->modelID);
|
||||||
auto weaponData =
|
if (model != nullptr) {
|
||||||
world->data->findModelInfo<SimpleModelInfo>(model);
|
itemTextureName = model->name;
|
||||||
if (weaponData != nullptr) {
|
|
||||||
itemTextureName = weaponData->name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Urgh
|
// Urgh
|
||||||
@ -179,25 +177,20 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
|
|||||||
glm::vec4(iconX, iconY, ui_weaponSize, ui_weaponSize));
|
glm::vec4(iconX, iconY, ui_weaponSize, ui_weaponSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current) {
|
if (weapon->fireType != WeaponData::MELEE) {
|
||||||
WeaponItem* wep = static_cast<WeaponItem*>(current);
|
const CharacterState& cs = player->getCharacter()->getCurrentState();
|
||||||
if (wep->getWeaponData()->fireType != WeaponData::MELEE) {
|
const CharacterWeaponSlot& slotInfo = cs.weapons[cs.currentWeapon];
|
||||||
const CharacterState& cs =
|
ti.text = GameStringUtil::fromString(
|
||||||
player->getCharacter()->getCurrentState();
|
std::to_string(slotInfo.bulletsClip) + "-" +
|
||||||
const CharacterWeaponSlot& slotInfo = cs.weapons[cs.currentWeapon];
|
std::to_string(slotInfo.bulletsTotal));
|
||||||
ti.text = GameStringUtil::fromString(
|
|
||||||
std::to_string(slotInfo.bulletsClip) + "-" +
|
|
||||||
std::to_string(slotInfo.bulletsTotal));
|
|
||||||
|
|
||||||
ti.baseColour = ui_shadowColour;
|
ti.baseColour = ui_shadowColour;
|
||||||
ti.font = 2;
|
ti.font = 2;
|
||||||
ti.size = ui_ammoSize;
|
ti.size = ui_ammoSize;
|
||||||
ti.align = TextRenderer::TextInfo::Center;
|
ti.align = TextRenderer::TextInfo::Center;
|
||||||
ti.screenPosition =
|
ti.screenPosition = glm::vec2(iconX + ui_weaponSize / 2.f,
|
||||||
glm::vec2(iconX + ui_weaponSize / 2.f,
|
iconY + ui_weaponSize - ui_ammoHeight);
|
||||||
iconY + ui_weaponSize - ui_ammoHeight);
|
render->text.renderText(ti);
|
||||||
render->text.renderText(ti);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <glm/gtx/string_cast.hpp>
|
#include <glm/gtx/string_cast.hpp>
|
||||||
#include <items/InventoryItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/InstanceObject.hpp>
|
#include <objects/InstanceObject.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
@ -279,11 +278,10 @@ Menu* DebugState::createWeaponMenu() {
|
|||||||
[=] { this->enterMenu(createDebugMenu()); },
|
[=] { this->enterMenu(createDebugMenu()); },
|
||||||
kDebugEntryHeight));
|
kDebugEntryHeight));
|
||||||
|
|
||||||
for (int i = 1; i < maxInventorySlots; ++i) {
|
for (int i = 1; i < kMaxInventorySlots; ++i) {
|
||||||
auto item = getWorld()->getInventoryItem(i);
|
|
||||||
auto& name = getWorld()->data->weaponData[i]->name;
|
auto& name = getWorld()->data->weaponData[i]->name;
|
||||||
m->addEntry(
|
m->addEntry(
|
||||||
Menu::lambda(name, [=] { giveItem(item); }, kDebugEntryHeight));
|
Menu::lambda(name, [=] { giveItem(i); }, kDebugEntryHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
@ -475,17 +473,14 @@ void DebugState::spawnFollower(unsigned int id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugState::giveItem(InventoryItem* item) {
|
void DebugState::giveItem(int slot) {
|
||||||
CharacterObject* player = nullptr;
|
CharacterObject* player = nullptr;
|
||||||
if (game->getPlayer()) {
|
if (game->getPlayer()) {
|
||||||
player = game->getPlayer()->getCharacter();
|
player = game->getPlayer()->getCharacter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player) {
|
if (player) {
|
||||||
player->addToInventory(item);
|
player->addToInventory(slot, 100);
|
||||||
auto& wep = player->getCurrentState().weapons[item->getInventorySlot()];
|
|
||||||
wep.bulletsTotal = 100;
|
|
||||||
wep.bulletsClip = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
|
|
||||||
void spawnVehicle(unsigned int id);
|
void spawnVehicle(unsigned int id);
|
||||||
void spawnFollower(unsigned int id);
|
void spawnFollower(unsigned int id);
|
||||||
void giveItem(InventoryItem* item);
|
void giveItem(int slot);
|
||||||
|
|
||||||
const ViewCamera& getCamera();
|
const ViewCamera& getCamera();
|
||||||
};
|
};
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
#include <ai/PlayerController.hpp>
|
#include <ai/PlayerController.hpp>
|
||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
|
#include <data/WeaponData.hpp>
|
||||||
#include <dynamics/CollisionInstance.hpp>
|
#include <dynamics/CollisionInstance.hpp>
|
||||||
#include <dynamics/RaycastCallbacks.hpp>
|
#include <dynamics/RaycastCallbacks.hpp>
|
||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/ItemPickup.hpp>
|
#include <objects/ItemPickup.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
@ -105,9 +105,9 @@ void IngameState::startTest() {
|
|||||||
getWorld()->state->playerObject = playerChar->getGameObjectID();
|
getWorld()->state->playerObject = playerChar->getGameObjectID();
|
||||||
|
|
||||||
glm::vec3 itemspawn(276.5f, -609.f, 36.5f);
|
glm::vec3 itemspawn(276.5f, -609.f, 36.5f);
|
||||||
for (int i = 1; i < maxInventorySlots; ++i) {
|
for (int i = 1; i < getWorld()->data->weaponData.size(); ++i) {
|
||||||
auto item = getWorld()->getInventoryItem(i);
|
auto& item = getWorld()->data->weaponData[i];
|
||||||
getWorld()->createPickup(itemspawn, item->getModelID(),
|
getWorld()->createPickup(itemspawn, item->modelID,
|
||||||
PickupObject::OnStreet);
|
PickupObject::OnStreet);
|
||||||
itemspawn.x += 2.5f;
|
itemspawn.x += 2.5f;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include "test_globals.hpp"
|
#include "test_globals.hpp"
|
||||||
|
|
||||||
@ -11,24 +10,17 @@ BOOST_AUTO_TEST_CASE(test_character_inventory) {
|
|||||||
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
||||||
BOOST_REQUIRE(character != nullptr);
|
BOOST_REQUIRE(character != nullptr);
|
||||||
|
|
||||||
auto item = Global::get().e->getInventoryItem(4);
|
character->addToInventory(1, 10);
|
||||||
auto fist = Global::get().e->getInventoryItem(0);
|
|
||||||
|
|
||||||
BOOST_REQUIRE(item != nullptr);
|
BOOST_CHECK_EQUAL(character->getActiveItem(), 0);
|
||||||
BOOST_REQUIRE(fist != nullptr);
|
|
||||||
BOOST_CHECK_NE(fist, item);
|
|
||||||
|
|
||||||
character->addToInventory(item);
|
character->setActiveItem(1);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(character->getActiveItem(), fist);
|
BOOST_CHECK_EQUAL(character->getActiveItem(), 1);
|
||||||
|
|
||||||
character->setActiveItem(item->getInventorySlot());
|
character->removeFromInventory(1);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(character->getActiveItem(), item);
|
BOOST_CHECK_EQUAL(character->getActiveItem(), 0);
|
||||||
|
|
||||||
character->removeFromInventory(item->getInventorySlot());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(character->getActiveItem(), fist);
|
|
||||||
|
|
||||||
Global::get().e->destroyObject(character);
|
Global::get().e->destroyObject(character);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <items/InventoryItem.hpp>
|
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/ItemPickup.hpp>
|
#include <objects/ItemPickup.hpp>
|
||||||
#include <objects/PickupObject.hpp>
|
#include <objects/PickupObject.hpp>
|
||||||
@ -65,16 +64,16 @@ BOOST_AUTO_TEST_CASE(test_item_pickup) {
|
|||||||
Global::get().e->createPedestrian(1, {30.1f, 0.f, 0.f});
|
Global::get().e->createPedestrian(1, {30.1f, 0.f, 0.f});
|
||||||
BOOST_REQUIRE(character != nullptr);
|
BOOST_REQUIRE(character != nullptr);
|
||||||
|
|
||||||
auto item = Global::get().e->getInventoryItem(3);
|
auto pistol = Global::get().d->weaponData[1].get();
|
||||||
BOOST_REQUIRE(item != nullptr);
|
auto model = Global::get().d->modelinfo[pistol->modelID].get();
|
||||||
|
|
||||||
ItemPickup* p = new ItemPickup(Global::get().e, {30.f, 0.f, 0.f},
|
ItemPickup* p = new ItemPickup(Global::get().e, {30.f, 0.f, 0.f}, model,
|
||||||
nullptr, PickupObject::OnStreet, item);
|
PickupObject::OnStreet, pistol);
|
||||||
|
|
||||||
Global::get().e->allObjects.push_back(p);
|
Global::get().e->allObjects.push_back(p);
|
||||||
|
|
||||||
// Check the characters inventory is empty.
|
// Check the characters inventory is empty.
|
||||||
for (int i = 0; i < maxInventorySlots; ++i) {
|
for (int i = 0; i < kMaxInventorySlots; ++i) {
|
||||||
BOOST_CHECK(character->getCurrentState().weapons[i].weaponId == 0);
|
BOOST_CHECK(character->getCurrentState().weapons[i].weaponId == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +83,7 @@ BOOST_AUTO_TEST_CASE(test_item_pickup) {
|
|||||||
auto& inventory = character->getCurrentState().weapons;
|
auto& inventory = character->getCurrentState().weapons;
|
||||||
BOOST_CHECK(std::any_of(std::begin(inventory), std::end(inventory),
|
BOOST_CHECK(std::any_of(std::begin(inventory), std::end(inventory),
|
||||||
[&](const CharacterWeaponSlot& i) {
|
[&](const CharacterWeaponSlot& i) {
|
||||||
return i.weaponId ==
|
return i.weaponId == pistol->inventorySlot;
|
||||||
item->getInventorySlot();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Global::get().e->destroyObject(p);
|
Global::get().e->destroyObject(p);
|
||||||
|
@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(TestProjectile) {
|
|||||||
auto character = Global::get().e->createPedestrian(1, {25.f, 0.f, 0.f});
|
auto character = Global::get().e->createPedestrian(1, {25.f, 0.f, 0.f});
|
||||||
BOOST_REQUIRE(character != nullptr);
|
BOOST_REQUIRE(character != nullptr);
|
||||||
|
|
||||||
auto wepdata = Global::get().e->data->weaponData[5];
|
auto wepdata = Global::get().e->data->weaponData[5].get();
|
||||||
|
|
||||||
auto projectile = new ProjectileObject(
|
auto projectile = new ProjectileObject(
|
||||||
Global::get().e, {26.f, 1.f, 10.f},
|
Global::get().e, {26.f, 1.f, 10.f},
|
||||||
@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(TestProjectile) {
|
|||||||
auto character = Global::get().e->createPedestrian(1, {25.f, 0.f, 0.f});
|
auto character = Global::get().e->createPedestrian(1, {25.f, 0.f, 0.f});
|
||||||
BOOST_REQUIRE(character != nullptr);
|
BOOST_REQUIRE(character != nullptr);
|
||||||
|
|
||||||
auto wepdata = Global::get().e->data->weaponData[6];
|
auto wepdata = Global::get().e->data->weaponData[6].get();
|
||||||
|
|
||||||
auto projectile = new ProjectileObject(
|
auto projectile = new ProjectileObject(
|
||||||
Global::get().e, {26.f, 1.f, 10.f},
|
Global::get().e, {26.f, 1.f, 10.f},
|
||||||
@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(TestProjectile) {
|
|||||||
auto character = Global::get().e->createPedestrian(1, {25.f, 0.f, 0.f});
|
auto character = Global::get().e->createPedestrian(1, {25.f, 0.f, 0.f});
|
||||||
BOOST_REQUIRE(character != nullptr);
|
BOOST_REQUIRE(character != nullptr);
|
||||||
|
|
||||||
auto wepdata = Global::get().e->data->weaponData[7];
|
auto wepdata = Global::get().e->data->weaponData[7].get();
|
||||||
|
|
||||||
auto projectile = new ProjectileObject(
|
auto projectile = new ProjectileObject(
|
||||||
Global::get().e, {26.f, 1.f, 10.f},
|
Global::get().e, {26.f, 1.f, 10.f},
|
||||||
|
Loading…
Reference in New Issue
Block a user