From 3b194c4ce81a4112bb4931516e3f6cb8a2e48c93 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:33:34 +0200 Subject: [PATCH 01/36] PlayerController: Remove outdated and unused movement code --- src/logic/PlayerController.cpp | 227 --------------------------------- 1 file changed, 227 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 5c9bf4cb..bee64913 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -821,233 +821,6 @@ void PlayerController::onUpdateByInput(float deltaTime) getModelVisual()->getAnimationHandler().setSpeedMultiplier(moveMod); m_AIHandler.playerUpdate(deltaTime); - return; - - // FIXME: Temporary test-code - static bool lastDraw = false; - - /* -#define SINGLE_ACTION_KEY(key, fn) { \ - static bool last = false; \ - if(inputGetKeyState(key) && !last)\ - last = true; \ - else if(!inputGetKeyState(key) && last){\ - last = false;\ - fn();\ - } } - - SINGLE_ACTION_KEY(entry::Key::KeyK, [&](){ - // Let all near NPCs draw their weapon - std::set nearNPCs = m_World.getScriptEngine().getNPCsInRadius(getEntityTransform().Translation(), 10.0f); - - for(const Handle::EntityHandle& h : nearNPCs) - { - VobTypes::NpcVobInformation npc = VobTypes::asNpcVob(m_World, h); - VobTypes::NPC_DrawMeleeWeapon(npc); - } - }); - - SINGLE_ACTION_KEY(entry::Key::KeyJ, [&](){ - // Let all near NPCs draw their weapon - std::set nearNPCs = m_World.getScriptEngine().getNPCsInRadius(getEntityTransform().Translation(), 10.0f); - - for(const Handle::EntityHandle& h : nearNPCs) - { - VobTypes::NpcVobInformation npc = VobTypes::asNpcVob(m_World, h); - VobTypes::NPC_UndrawWeapon(npc); - } - }); - - SINGLE_ACTION_KEY(entry::Key::KeyH, [&](){ - // Let all near NPCs draw their weapon - std::set nearNPCs = m_World.getScriptEngine().getNPCsInRadius(getEntityTransform().Translation(), 10.0f); - - for(const Handle::EntityHandle& h : nearNPCs) - { - VobTypes::NpcVobInformation npc = VobTypes::asNpcVob(m_World, h); - npc.playerController->attackFront(); - } - }); - */ - if (m_isDrawWeaponMelee) - { - if (!lastDraw) - { - lastDraw = true; - - if (m_EquipmentState.activeWeapon.isValid()) - undrawWeapon(); - else - drawWeaponMelee(); - } - - // Don't overwrite the drawing animation - return; - } - else if (!m_isDrawWeaponMelee && lastDraw) - { - lastDraw = false; - } - - m_NoAniRootPosHack = false; - - if (m_EquipmentState.weaponMode == EWeaponMode::WeaponNone) - { - static std::string lastMovementAni = ""; - auto manageAnimation = [&](ModelVisual::EModelAnimType groundAniType, ModelVisual::EModelAnimType waterAniType) { - if (getSurfaceMaterial() == ZenLoad::MaterialGroup::WATER) - { - if (m_isSwimming) - { - model->setAnimation(waterAniType); - } - else - { - model->setAnimation(groundAniType); - } - } - else if (getSurfaceMaterial() != ZenLoad::MaterialGroup::UNDEF) - { - model->setAnimation(groundAniType); - } - else - { - //TODO this happens more than it should, there seems to be too much undefined materials, find out why - model->setAnimation(groundAniType); // Ground animation is the default, we don't want the NPCs to start swimming in soil - } - if (getModelVisual()->getAnimationHandler().getActiveAnimationPtr()) - lastMovementAni = getModelVisual()->getAnimationHandler().getActiveAnimationPtr()->m_Name; - m_NoAniRootPosHack = true; - }; - if (m_isStrafeLeft) - { - manageAnimation(ModelVisual::EModelAnimType::StrafeLeft, ModelVisual::EModelAnimType::SwimTurnLeft); - } - else if (m_isStrafeRight) - { - manageAnimation(ModelVisual::EModelAnimType::StrafeRight, ModelVisual::EModelAnimType::SwimTurnRight); - } - else if (m_isTurnLeft && !m_isForward) - { - manageAnimation(ModelVisual::EModelAnimType::TurnLeft, ModelVisual::EModelAnimType::SwimTurnLeft); - } - else if (m_isTurnRight && !m_isForward) - { - manageAnimation(ModelVisual::EModelAnimType::TurnRight, ModelVisual::EModelAnimType::SwimTurnRight); - } - else if (m_isForward) - { - manageAnimation(m_MoveState.ground.waterDepth > m_wadeThreshold ? ModelVisual::EModelAnimType::Wade : ModelVisual::EModelAnimType::Run, ModelVisual::EModelAnimType::SwimF); - } - else if (m_isBackward) - { - manageAnimation(ModelVisual::EModelAnimType::Backpedal, ModelVisual::EModelAnimType::SwimB); - } - // else if(inputGetKeyState(entry::Key::KeyQ)) - // { - // model->setAnimation(ModelVisual::EModelAnimType::AttackFist); - // } - else if (getModelVisual()->getAnimationHandler().getActiveAnimationPtr() && getModelVisual()->getAnimationHandler().getActiveAnimationPtr()->m_Name == lastMovementAni) - { - manageAnimation(ModelVisual::EModelAnimType::Idle, ModelVisual::EModelAnimType::Swim); - m_NoAniRootPosHack = true; - } - } - // else - // { - // std::map> aniMap = - // { - // {EWeaponMode::Weapon1h, { ModelVisual::EModelAnimType::Attack1h_L, - // ModelVisual::EModelAnimType::Attack1h_R, - // ModelVisual::EModelAnimType::Run1h, - // ModelVisual::EModelAnimType::Backpedal1h, - // ModelVisual::EModelAnimType::Attack1h, - // ModelVisual::EModelAnimType::Idle1h}}, - - // {EWeaponMode::Weapon2h, { ModelVisual::EModelAnimType::Attack2h_L, - // ModelVisual::EModelAnimType::Attack2h_R, - // ModelVisual::EModelAnimType::Run2h, - // ModelVisual::EModelAnimType::Backpedal2h, - // ModelVisual::EModelAnimType::Attack2h, - // ModelVisual::EModelAnimType::Idle2h}}, - - // {EWeaponMode::WeaponBow, { ModelVisual::EModelAnimType::IdleBow, - // ModelVisual::EModelAnimType::IdleBow, - // ModelVisual::EModelAnimType::RunBow, - // ModelVisual::EModelAnimType::BackpedalBow, - // ModelVisual::EModelAnimType::AttackBow, - // ModelVisual::EModelAnimType::IdleBow}}, - - // {EWeaponMode::WeaponCrossBow, { ModelVisual::EModelAnimType::IdleCBow, - // ModelVisual::EModelAnimType::IdleCBow, - // ModelVisual::EModelAnimType::RunCBow, - // ModelVisual::EModelAnimType::BackpedalCBow, - // ModelVisual::EModelAnimType::AttackCBow, - // ModelVisual::EModelAnimType::IdleCBow}} - // }; - - // if(inputGetKeyState(entry::Key::KeyA)) - // { - // model->setAnimation(aniMap[m_EquipmentState.weaponMode][0]); - // } - // else if(inputGetKeyState(entry::Key::KeyD)) - // { - // model->setAnimation(aniMap[m_EquipmentState.weaponMode][1]); - // } - // else if(inputGetKeyState(entry::Key::KeyW)) - // { - // model->setAnimation(aniMap[m_EquipmentState.weaponMode][2]); - // } - // else if(inputGetKeyState(entry::Key::KeyS)) - // { - // model->setAnimation(aniMap[m_EquipmentState.weaponMode][3]); - // } - // else if(inputGetKeyState(entry::Key::KeyQ)) - // { - // model->setAnimation(aniMap[m_EquipmentState.weaponMode][4]); - // } - // else { - // model->setAnimation(aniMap[m_EquipmentState.weaponMode][5]); - // } - // } - - float yaw = 0.0f; - const float turnSpeed = 2.5f; - - if (!m_AIState.usedMob.isValid()) - { - if (m_isTurnLeft) - { - yaw += turnSpeed * deltaTime; - m_NoAniRootPosHack = true; - } - else if (m_isTurnRight) - { - yaw -= turnSpeed * deltaTime; - m_NoAniRootPosHack = true; - } - } - - // No direction key pressed - if (!m_NoAniRootPosHack) - return; - - // Apply animation-velocity - Math::float3 rootNodeVel = model->getAnimationHandler().getRootNodeVelocityTotal() * deltaTime; - - float angle = atan2(m_MoveState.direction.z, m_MoveState.direction.x); - m_MoveState.direction = Math::float3(cos(angle + yaw), 0, sin(angle + yaw)); - angle = atan2(m_MoveState.direction.z, m_MoveState.direction.x); - - m_MoveState.position += Math::Matrix::CreateRotationY(-angle + Math::PI * 0.5f) * rootNodeVel; - - setDirection(m_MoveState.direction); - - //Math::Matrix newTransform = Math::Matrix::CreateTranslation(m_MoveState.position) * Math::Matrix::CreateRotationY(angle + yaw); - //setEntityTransform(newTransform); - - placeOnGround(); - resetKeyStates(); } void PlayerController::attackFront() From dda8bdcd0ed48bdfdac64e070d6b5dcac1576fc7 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:44:20 +0200 Subject: [PATCH 02/36] PlayerController: Removed more old movement code (broke standing up after being unconscious) --- src/logic/PlayerController.cpp | 51 ++++------------------------------ src/logic/PlayerController.h | 7 ----- 2 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index bee64913..50b8ea72 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -109,15 +109,6 @@ PlayerController::PlayerController(World::WorldInstance& world, m_RefuseTalkTime = 0; - m_isDrawWeaponMelee = false; - m_isForward = false; - m_isBackward = false; - m_isTurnLeft = false; - m_isTurnRight = false; - m_isStrafeLeft = false; - m_isStrafeRight = false; - m_isSwimming = false; - m_LastAniRootPosUpdatedAniHash = 0; m_NoAniRootPosHack = false; @@ -724,18 +715,14 @@ void PlayerController::placeOnGround() closestResult = newDistance; } } - shallowWater = closestHitGroundSurface.hitPosition.y < waterHitSurface.hitPosition.y && waterHitSurface.hitPosition.y <= highestHitSurface.hitPosition.y; + auto manageState = [&]() { if (fellThrough) { placeOnSurface(highestHitSurface); return; } - if ((m_isSwimming = shallowWater && m_MoveState.ground.waterDepth > m_swimThreshold)) - { - placeOnSurface(waterHitSurface); - return; - } + placeOnSurface(closestHitGroundSurface); }; manageState(); @@ -790,12 +777,12 @@ void PlayerController::onUpdateByInput(float deltaTime) if (m_World.getEngine()->getHud().isMenuActive()) resetKeyStates(); - // Stand up if wounded and forward is pressed + // Stand up if wounded if (getModelVisual()->isAnimPlaying("S_WOUNDEDB") && getBodyState() == EBodyState::BS_UNCONSCIOUS) { // Only stand up if the unconscious-state has ended (aka. is not valid anymore) // Otherwise, the player would fall down immediately - if (m_isForward && m_AIStateMachine.isStateActive()) + if (m_AIStateMachine.isStateActive()) { // FIXME: End UNCONSCIOUS-state here @@ -2161,12 +2148,7 @@ void PlayerController::traceDownNPCGround() void PlayerController::resetKeyStates() { - m_isStrafeLeft = false; - m_isStrafeRight = false; m_isForward = false; - m_isBackward = false; - m_isTurnLeft = false; - m_isTurnRight = false; m_MoveSpeed1 = false; m_MoveSpeed2 = false; } @@ -2365,9 +2347,6 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f switch (actionType) { - case ActionType::PlayerDrawWeaponMelee: - m_isDrawWeaponMelee = triggered; - break; case ActionType::PlayerForward: { // Increment state, if currently using a mob @@ -2384,10 +2363,6 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f } } } - else - { - m_isForward = m_isForward || triggered; - } } break; case ActionType::PlayerBackward: @@ -2406,24 +2381,9 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f } } } - else - { - m_isBackward = m_isBackward || triggered; - } } break; - case ActionType::PlayerTurnLeft: - m_isTurnLeft = m_isTurnLeft || triggered; - break; - case ActionType::PlayerTurnRight: - m_isTurnRight = m_isTurnRight || triggered; - break; - case ActionType::PlayerStrafeLeft: - m_isStrafeLeft = m_isStrafeLeft || triggered; - break; - case ActionType::PlayerStrafeRight: - m_isStrafeRight = m_isStrafeRight || triggered; - break; + case ActionType::DebugMoveSpeed: m_MoveSpeed1 = m_MoveSpeed1 || triggered; break; @@ -2597,7 +2557,6 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f break; default: - assert(false); break; } } diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index d9d759db..35ed9887 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -615,14 +615,7 @@ namespace Logic /** * Key states */ - bool m_isDrawWeaponMelee; bool m_isForward; - bool m_isBackward; - bool m_isTurnLeft; - bool m_isTurnRight; - bool m_isStrafeLeft; - bool m_isStrafeRight; - bool m_isSwimming; bool m_MoveSpeed1, m_MoveSpeed2; /** From 4ffa8fb3fa70e08f624d8d142ea86a17fa6c509b Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:46:09 +0200 Subject: [PATCH 03/36] PlayerController: Remove old attacking-code (unused) --- src/logic/PlayerController.cpp | 75 ---------------------------------- src/logic/PlayerController.h | 7 ---- 2 files changed, 82 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 50b8ea72..62993520 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -810,81 +810,6 @@ void PlayerController::onUpdateByInput(float deltaTime) m_AIHandler.playerUpdate(deltaTime); } -void PlayerController::attackFront() -{ - if (m_EquipmentState.weaponMode == EWeaponMode::WeaponNone) - return; - - ModelVisual::EModelAnimType type = ModelVisual::EModelAnimType::NUM_ANIMATIONS; - switch (m_EquipmentState.weaponMode) - { - case EWeaponMode::Weapon1h: - type = ModelVisual::EModelAnimType::Attack1h; - break; - case EWeaponMode::Weapon2h: - type = ModelVisual::EModelAnimType::Attack2h; - break; - case EWeaponMode::WeaponBow: - type = ModelVisual::EModelAnimType::AttackBow; - break; - case EWeaponMode::WeaponCrossBow: - type = ModelVisual::EModelAnimType::AttackCBow; - break; - case EWeaponMode::WeaponFist: - type = ModelVisual::EModelAnimType::AttackFist; - break; - //case EWeaponMode::WeaponMagic: type = ModelVisual::EModelAnimType::AttackMagic; break; // TODO: Magic - default: - break; - } - - if (type != ModelVisual::EModelAnimType::NUM_ANIMATIONS) - getModelVisual()->playAnimation(type); -} - -void PlayerController::attackLeft() -{ - if (m_EquipmentState.weaponMode == EWeaponMode::WeaponNone) - return; - - ModelVisual::EModelAnimType type = ModelVisual::EModelAnimType::NUM_ANIMATIONS; - switch (m_EquipmentState.weaponMode) - { - case EWeaponMode::Weapon1h: - type = ModelVisual::EModelAnimType::Attack1h_L; - break; - case EWeaponMode::Weapon2h: - type = ModelVisual::EModelAnimType::Attack2h_L; - break; - default: - break; - } - - if (type != ModelVisual::EModelAnimType::NUM_ANIMATIONS) - getModelVisual()->playAnimation(type); -} - -void PlayerController::attackRight() -{ - if (m_EquipmentState.weaponMode == EWeaponMode::WeaponNone) - return; - - ModelVisual::EModelAnimType type = ModelVisual::EModelAnimType::NUM_ANIMATIONS; - switch (m_EquipmentState.weaponMode) - { - case EWeaponMode::Weapon1h: - type = ModelVisual::EModelAnimType::Attack1h_R; - break; - case EWeaponMode::Weapon2h: - type = ModelVisual::EModelAnimType::Attack2h_L; - break; - default: - break; - } - - if (type != ModelVisual::EModelAnimType::NUM_ANIMATIONS) - getModelVisual()->playAnimation(type); -} void PlayerController::onMessage(SharedEMessage message, Handle::EntityHandle sourceVob) { diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 35ed9887..3b981489 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -264,13 +264,6 @@ namespace Logic */ Daedalus::GEngineClasses::C_Npc& getScriptInstance(); - /** - * Front/Right/Left-Attack with the current weapon - */ - void attackFront(); - void attackLeft(); - void attackRight(); - /** * @return True, if this is the currently controlled character */ From 96bfc352cc2a2316a2ad78f798eae6ca928d9692 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:47:17 +0200 Subject: [PATCH 04/36] PlayerController: Remove commented out debug-drawing-code --- src/logic/PlayerController.cpp | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 62993520..db5387c0 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -257,40 +257,6 @@ void PlayerController::travelPath() void PlayerController::onDebugDraw() { - /*if (!m_MoveState.currentPath.empty()) - { - Render::debugDrawPath(m_World.getWaynet(), m_MoveState.currentPath); - }*/ - - // Math::float3 to = getEntityTransform().Translation() + Math::float3(0.0f, -1.0f, 0.0f); - // Math::float3 from = getEntityTransform().Translation() + Math::float3(0.0f, 1.0f, 0.0f); - // - // Physics::RayTestResult hit = m_World.getPhysicsSystem().raytrace(from, to, Physics::CollisionShape::CT_WorldMesh); - // - // if (hit.hasHit) - // { - // ddDrawAxis(hit.hitPosition.x, hit.hitPosition.y, hit.hitPosition.z); - // - // float shadow = m_World.getWorldMesh().interpolateTriangleShadowValue(hit.hitTriangleIndex, hit.hitPosition); - // - // if(getModelVisual()) - // getModelVisual()->setShadowValue(shadow); - // - // Math::float3 v3[3]; - // ZenLoad::zCMaterialData data = m_World.getWorldMesh().GetMatData(hit.hitTriangleIndex); - // uint8_t matgroup; - // m_World.getWorldMesh().getTriangle(hit.hitTriangleIndex, v3, matgroup); - // // if (isPlayerControlled()) - // // { - // // LogInfo() << "matgroup : " << std::bitset<8>(data.matGroup); - // // LogInfo() << "matname: " << data.matName; - // // } - // for(int i=0;i<3;i++) - // { - // ddDrawAxis(v3[i].x, v3[i].y, v3[i].z); - // } - // } - if (isPlayerControlled()) { VobTypes::NpcVobInformation npc = VobTypes::asNpcVob(m_World, m_Entity); From cea5e21732b771d9f3d3b14046c068a24bbe29a9 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:49:46 +0200 Subject: [PATCH 05/36] PlayerController: Remove old function about routes --- src/logic/PlayerController.cpp | 6 ------ src/logic/PlayerController.h | 5 ----- 2 files changed, 11 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index db5387c0..63cb60eb 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -1455,12 +1455,6 @@ void PlayerController::standUp(bool walkingAllowed, bool startAniTransition) m_AIHandler.standup(); } -void PlayerController::stopRoute() -{ - m_MoveState.currentPath.clear(); - m_RoutineState.entityTarget.invalidate(); -} - void PlayerController::setRoutineFunc(size_t symRoutine) { getScriptInstance().daily_routine = static_cast(symRoutine); diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 3b981489..e991b628 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -139,11 +139,6 @@ namespace Logic void gotoVob(Handle::EntityHandle vob); void gotoPosition(const Math::float3& position); - /** - * Stops going along the current route - */ - void stopRoute(); - /** * Teleports the entity to the given waypoint * @param Waypoint index to go to From c69d6649f0a629adf796965e8926b00f7bc479b2 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:50:41 +0200 Subject: [PATCH 06/36] PlayerController: Remove commented out code used for testing npc-import --- src/logic/PlayerController.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 63cb60eb..3a904ba7 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -1806,11 +1806,7 @@ void PlayerController::importObject(const json& j) Handle::EntityHandle PlayerController::importPlayerController(World::WorldInstance& world, const json& j) { unsigned int instanceSymbol = j["scriptObj"]["instanceSymbol"]; - - /*std::string name = j["scriptObj"]["name"][0]; - if(name != "Diego" && name != "ich") - return Handle::EntityHandle();*/ - + // Create npc Handle::EntityHandle e = VobTypes::Wld_InsertNpc(world, instanceSymbol); From 7d371ee90d76eb582b543e05e38b5c2a19b1f9ac Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 00:58:18 +0200 Subject: [PATCH 07/36] PlayerController: Move getting worldmesh-triangle material to worldmesh-class --- src/engine/WorldMesh.cpp | 9 +++++++++ src/engine/WorldMesh.h | 5 +++++ src/logic/PlayerController.cpp | 28 ++++++++-------------------- src/logic/PlayerController.h | 4 ---- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/engine/WorldMesh.cpp b/src/engine/WorldMesh.cpp index 477adb11..6ecdbe59 100644 --- a/src/engine/WorldMesh.cpp +++ b/src/engine/WorldMesh.cpp @@ -52,3 +52,12 @@ ZenLoad::zCMaterialData WorldMesh::getMatData(size_t triangleIdx) const assert(m_WorldMeshData.triangles[triangleIdx].submeshIndex < m_WorldMeshData.subMeshes.size()); return m_WorldMeshData.subMeshes[m_WorldMeshData.triangles[triangleIdx].submeshIndex].material; } + +ZenLoad::MaterialGroup WorldMesh::getMaterialGroupOfTriangle(uint32_t triangleIdx) +{ + Math::float3 v3[3]; + uint8_t matgroup; + // Beware! If triangle index is given such that the triangle is a building triangle of a VOB, this function will return material of the underlying worldmesh!!! + getTriangle(triangleIdx, v3, matgroup); + return static_cast(matgroup); +} diff --git a/src/engine/WorldMesh.h b/src/engine/WorldMesh.h index 1ebccc51..9278cc8c 100644 --- a/src/engine/WorldMesh.h +++ b/src/engine/WorldMesh.h @@ -38,6 +38,11 @@ namespace World */ void getTriangle(size_t triangleIdx, Math::float3* v3, uint8_t& matgroup); + /** + * Returns material group of give triangle index + */ + ZenLoad::MaterialGroup getMaterialGroupOfTriangle(uint32_t triangleIdx); + /** * @return Boundingbox max/min */ diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 3a904ba7..03dbc686 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -578,7 +578,9 @@ void PlayerController::placeOnSurface(const Physics::RayTestResult& hit) { if (DEBUG_PLAYER) { - LogInfo() << (int)getMaterial(hit.hitTriangleIndex) << ", Placing hero at position: " << hit.hitPosition.x << ", " << hit.hitPosition.y << ", " << hit.hitPosition.z; + LogInfo() << (int)m_World.getWorldMesh().getMaterialGroupOfTriangle(hit.hitTriangleIndex) + << ", Placing hero at position: " + << hit.hitPosition.x << ", " << hit.hitPosition.y << ", " << hit.hitPosition.z; } Math::Matrix m = getEntityTransform(); @@ -668,7 +670,7 @@ void PlayerController::placeOnGround() highestHitY = result.hitPosition.y; highestHitSurface = result; } - auto material = getMaterial(result.hitTriangleIndex); + auto material = m_World.getWorldMesh().getMaterialGroupOfTriangle(result.hitTriangleIndex); if (result.hitFlags == Physics::CollisionShape::CT_Object) material = ZenLoad::MaterialGroup::UNDEF; // we don't want underlying worldmesh material in this case if (material == ZenLoad::MaterialGroup::WATER) { @@ -1806,7 +1808,7 @@ void PlayerController::importObject(const json& j) Handle::EntityHandle PlayerController::importPlayerController(World::WorldInstance& world, const json& j) { unsigned int instanceSymbol = j["scriptObj"]["instanceSymbol"]; - + // Create npc Handle::EntityHandle e = VobTypes::Wld_InsertNpc(world, instanceSymbol); @@ -1924,20 +1926,12 @@ void PlayerController::updateStatusScreen(UI::Menu_Status& statsScreen) statsScreen.setLearnPoints(stats.lp); } -ZenLoad::MaterialGroup PlayerController::getMaterial(uint32_t triangleIdx) -{ - Math::float3 v3[3]; - uint8_t matgroup; - // Beware! If triangle index is given such that the triangle is a building triangle of a VOB, this function will return material of the underlying worldmesh!!! - m_World.getWorldMesh().getTriangle(triangleIdx, v3, matgroup); - return static_cast(matgroup); -} ZenLoad::MaterialGroup PlayerController::getSurfaceMaterial() { if (m_MoveState.ground.successful) { - return getMaterial(m_MoveState.ground.triangleIndex); + return m_World.getWorldMesh().getMaterialGroupOfTriangle(m_MoveState.ground.triangleIndex); } else { @@ -1979,13 +1973,7 @@ void PlayerController::traceDownNPCGround() { auto diff = std::abs(entityPos.y - a.hitPosition.y); - if (ZenLoad::MaterialGroup::WATER == getMaterial(a.hitTriangleIndex)) - { - resultWater = a; - waterSurfacePos = a.hitPosition.y; - waterMatFound = true; // found water material - } - else if (closestGroundSurfacePos > diff) + if (closestGroundSurfacePos > diff) { result = a; closestGroundSurfacePos = diff; @@ -2123,7 +2111,7 @@ void PlayerController::AniEvent_SFXGround(const ZenLoad::zCModelScriptEventSfx& if (m_MoveState.ground.successful) { // Play sound depending on ground type - ZenLoad::MaterialGroup mat = getMaterial(m_MoveState.ground.triangleIndex); + ZenLoad::MaterialGroup mat = getSurfaceMaterial(); float range = sfx.m_Range != 0.0f ? sfx.m_Range : DEFAULT_CHARACTER_SOUND_RANGE; diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index e991b628..d884bddd 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -380,10 +380,6 @@ namespace Logic */ ZenLoad::MaterialGroup getSurfaceMaterial(); - /** - * Returns material data of give triangle index - */ - ZenLoad::MaterialGroup getMaterial(uint32_t triangleIdx); /** * @return Item this NPC is currently interacting with */ From 8a96e77796afeffa4127627e5aceb879f0b9e9a1 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 01:02:44 +0200 Subject: [PATCH 08/36] PlayerController: Remove last bits of old routine-handling (following) --- src/logic/PlayerController.cpp | 11 ----------- src/logic/PlayerController.h | 15 +-------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 03dbc686..b864c6b7 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -130,17 +130,6 @@ void PlayerController::onUpdate(float deltaTime) ModelVisual* model = getModelVisual(); - // Build the route to follow this entity - if (m_RoutineState.entityTarget.isValid()) - { - Math::float3 targetPos = m_World.getEntity(m_RoutineState.entityTarget) - .m_WorldMatrix.Translation(); - - // FIXME: Doing this every frame is too often - size_t targetWP = World::Waynet::findNearestWaypointTo(m_World.getWaynet(), targetPos); - - gotoWaypoint(targetWP); - } m_NoAniRootPosHack = false; if (model) diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index d884bddd..b0119879 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -97,8 +97,6 @@ namespace Logic */ EControllerType getControllerType() override { return EControllerType::PlayerController; } - void setFollowTarget(Handle::EntityHandle e) { m_RoutineState.entityTarget = e; } - /** * Called when the models visual changed */ @@ -465,18 +463,7 @@ namespace Logic * Moves the NPC to the next waypoint of the current path */ void travelPath(); - - /** - * Current routine state - */ - struct - { - /** - * Target of where the NPC should keep trying to go to - */ - Handle::EntityHandle entityTarget; - } m_RoutineState; - + struct { // Waypoint this NPC is closest to/was last positioned at From 1228c2528cb11b6b12e0dffdc02a249c34cb2036 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 01:04:01 +0200 Subject: [PATCH 09/36] PlayerController: Remove last bits about old route-travelling --- src/logic/PlayerController.cpp | 1 - src/logic/PlayerController.h | 14 +------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index b864c6b7..9ded2213 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -89,7 +89,6 @@ PlayerController::PlayerController(World::WorldInstance& world, , m_PathFinder(world) { m_AIState.closestWaypoint = 0; - m_MoveState.currentPathPerc = 0; m_NPCProperties.moveSpeed = 7.0f; m_NPCProperties.enablePhysics = true; diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index b0119879..508fd217 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -463,7 +463,7 @@ namespace Logic * Moves the NPC to the next waypoint of the current path */ void travelPath(); - + struct { // Waypoint this NPC is closest to/was last positioned at @@ -482,18 +482,6 @@ namespace Logic struct { - // Path the NPC is currently trying to take (To m_AIState.targetWaypoint) - std::vector currentPath; - - // Node the NPC is currently going to on the path - size_t targetNode; - - // Percentage of how far the NPC has gotten so far on the current path - float currentPathPerc; - - // Length of the current route - float currentRouteLength; - // Where the npc currently is Math::float3 position; From 81f45018eb5be05d44be9480d439fba7df652a41 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 01:05:12 +0200 Subject: [PATCH 10/36] PlayerController: Remove old movespeed-property --- src/logic/PlayerController.cpp | 1 - src/logic/PlayerController.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 9ded2213..2feb2e82 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -89,7 +89,6 @@ PlayerController::PlayerController(World::WorldInstance& world, , m_PathFinder(world) { m_AIState.closestWaypoint = 0; - m_NPCProperties.moveSpeed = 7.0f; m_NPCProperties.enablePhysics = true; m_MoveState.direction = Math::float3(1, 0, 0); diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 508fd217..804c3039 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -501,9 +501,6 @@ namespace Logic struct { - // Move speed in m/s - float moveSpeed; - // BBox for collision Math::float3 collisionBBox[2]; From e3429dd7a6e09a91e2c9bee23047304d46b6c201 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 01:06:42 +0200 Subject: [PATCH 11/36] PlayerController: Minor cleanup --- src/logic/PlayerController.cpp | 1 - src/logic/PlayerController.h | 10 +++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 2feb2e82..85173307 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -2004,7 +2004,6 @@ void PlayerController::traceDownNPCGround() void PlayerController::resetKeyStates() { - m_isForward = false; m_MoveSpeed1 = false; m_MoveSpeed2 = false; } diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 804c3039..39987951 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -571,7 +571,6 @@ namespace Logic /** * Key states */ - bool m_isForward; bool m_MoveSpeed1, m_MoveSpeed2; /** @@ -584,10 +583,12 @@ namespace Logic bool isAttached; int32_t m_Num; }; + /** * Stores active pfx handler associated with this PlayerController (one shot) */ std::vector m_activePfxEvents; + /** * Stores ended pfx handler (emitter don't spawn new particles) * After all particles are dead, updatePfx() will remove these elements from this vector @@ -599,6 +600,7 @@ namespace Logic * @param e pfxEvent */ void updatePfxPosition(const pfxEvent &e); + /** * Upates the pfx for this player (removes dead emitter) * When "ATTACH" keyword is used, the position is also changed. @@ -614,11 +616,5 @@ namespace Logic // Main noise sound slot. Other sounds using it won't play if there is already a sound playing here. Utils::Ticket m_MainNoiseSoundSlot; - - /** - * Contstants - */ - static constexpr float m_swimThreshold = 1.3; // TODO Adjust the value to reflect original game experiece - static constexpr float m_wadeThreshold = 0.5; // TODO Adjust the value to reflect original game experiece }; } From 91c59e110eb120b03a4dd0b2f3c90a21e7406936 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 20 Jun 2018 01:08:23 +0200 Subject: [PATCH 12/36] PlayerController: Remove some useless comments --- src/logic/PlayerController.h | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 39987951..6d7bacc3 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -539,28 +539,11 @@ namespace Logic Daedalus::GameState::ItemHandle equippedAmulet; } equippedItems; } m_EquipmentState; - - /** - * This players inventory - */ + Inventory m_Inventory; - - /** - * State manager - */ NpcScriptState m_AIStateMachine; - - /** - * Animation handler - */ NpcAnimationHandler m_NPCAnimationHandler; - - /** - * AI/Input handler - */ NpcAIHandler m_AIHandler; - - // Route-information Pathfinder m_PathFinder; /** From f2662552d87394e6c100796a485502e1def4841d Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:22:53 +0200 Subject: [PATCH 13/36] Lib: Added optional-submodule --- .gitmodules | 3 +++ lib/optional | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/optional diff --git a/.gitmodules b/.gitmodules index d0c91b5a..8fd7574a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "lib/libdmusic"] path = lib/libdmusic url = https://github.com/frabert/libdmusic.git +[submodule "lib/optional"] + path = lib/optional + url = https://github.com/TartanLlama/optional.git diff --git a/lib/optional b/lib/optional new file mode 160000 index 00000000..effc9411 --- /dev/null +++ b/lib/optional @@ -0,0 +1 @@ +Subproject commit effc9411169fc983a4647b57f5669c68b2893421 From 248336e2326f6dd29c3fd999bab7b2af6d908c28 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:23:51 +0200 Subject: [PATCH 14/36] CMake: Add optional to include path --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ece235..3a991b87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,7 @@ else() endif() add_subdirectory(lib/adpcm) +include_directories(lib/optional) add_subdirectory(src/target) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT REGoth) From ecf3b8b9b1eb85054c44e2cc17bce2fa9a6701ea Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:25:05 +0200 Subject: [PATCH 15/36] CharacterEquipment: Add first draft of equipment handling class (to be extracted from PlayerController) --- src/logic/CharacterEquipment.cpp | 318 +++++++++++++++++++++++++++++++ src/logic/CharacterEquipment.h | 160 ++++++++++++++++ 2 files changed, 478 insertions(+) create mode 100644 src/logic/CharacterEquipment.cpp create mode 100644 src/logic/CharacterEquipment.h diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp new file mode 100644 index 00000000..d36e1972 --- /dev/null +++ b/src/logic/CharacterEquipment.cpp @@ -0,0 +1,318 @@ +// +// Created by andre on 28.06.18. +// + +#include "CharacterEquipment.h" +#include +#include +#include + +using namespace Logic; + +CharacterEquipment::CharacterEquipment(World::WorldInstance& world, Handle::EntityHandle characterEntity) + : m_CharacterEntity(characterEntity) + , m_World(world) +{ +} + +bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) +{ + if (!isItemTypeCorrectForSlot(item, slot)) + return false; + + switch (getKindOfItem(item)) + { + case Kind::MELEE: + return equipMelee(item); + + case Kind::BOW: + return equipBow(item); + + case Kind::AMULET: + return equipAmulet(item); + + case Kind::RING: + return equipRing(item, slot); + + case Kind::MAGIC: + return equipMagic(item, slot); + + case Kind::BELT: + return equipBelt(item); + + case Kind::OTHER: + default: + return false; + } + + return true; +} + +bool Logic::CharacterEquipment::equipMelee(ItemHandle item) +{ + setItemInSlot(item, Slot::MELEE); + return true; +} + +bool Logic::CharacterEquipment::equipBow(ItemHandle item) +{ + setItemInSlot(item, Slot::BOW); + return true; +} + +bool Logic::CharacterEquipment::equipAmulet(ItemHandle item) +{ + setItemInSlot(item, Slot::AMULET); + return true; +} + +bool Logic::CharacterEquipment::equipRing(ItemHandle item, Slot slot) +{ + setItemInSlot(item, slot); + return true; +} + +bool Logic::CharacterEquipment::equipMagic(ItemHandle item, Slot slot) +{ + setItemInSlot(item, slot); + return true; +} + +bool Logic::CharacterEquipment::equipBelt(ItemHandle item) +{ + setItemInSlot(item, Slot::BELT); + return true; +} + +tl::optional CharacterEquipment::getCorrectSlotForItem(ItemHandle item) const +{ + switch (getKindOfItem(item)) + { + case Kind::MELEE: + return Slot::MELEE; + case Kind::BOW: + return Slot::BOW; + case Kind::AMULET: + return Slot::AMULET; + case Kind::RING: + return Slot::RING_LEFT; + case Kind::MAGIC: + return Slot::MAGIC_0; + case Kind::BELT: + return Slot::BELT; + case Kind::OTHER: + default: + return tl::nullopt; + } +} + +CharacterEquipment::Kind CharacterEquipment::getKindOfItem(ItemHandle item) const +{ + using Daedalus::GEngineClasses::C_Item; + auto itemDataOpt = getDataOfItem(item); + + if (!itemDataOpt) + return Kind::OTHER; + + auto& itemData = *itemDataOpt; + + // Magic can only be identified through the mainflags + if ((itemData.mainflag & C_Item::ITM_CAT_RUNE) != 0) + return Kind::MAGIC; + + if ((itemData.mainflag & C_Item::ITM_CAT_MAGIC) != 0) + return Kind::MAGIC; + + std::pair pairs[] = { + {C_Item::Flags::ITEM_DAG, Kind::MELEE}, + {C_Item::Flags::ITEM_SWD, Kind::MELEE}, + {C_Item::Flags::ITEM_AXE, Kind::MELEE}, + {C_Item::Flags::ITEM_2HD_SWD, Kind::MELEE}, + {C_Item::Flags::ITEM_2HD_AXE, Kind::MELEE}, + {C_Item::Flags::ITEM_BOW, Kind::BOW}, + {C_Item::Flags::ITEM_CROSSBOW, Kind::BOW}, + {C_Item::Flags::ITEM_AMULET, Kind::AMULET}, + {C_Item::Flags::ITEM_RING, Kind::RING}, + {C_Item::Flags::ITEM_BELT, Kind::BELT}, + {C_Item::Flags::ITEM_MISSION, Kind::OTHER}, + }; + + for (auto& p : pairs) + { + if (itemData.flags & p.first) + return p.second; + } + + return Kind::OTHER; +} + +tl::optional CharacterEquipment::findAnyFreeMagicSlot() const +{ + Slot possibleSlots[] = { + Slot::MAGIC_0, + Slot::MAGIC_1, + Slot::MAGIC_2, + Slot::MAGIC_3, + Slot::MAGIC_4, + Slot::MAGIC_5, + Slot::MAGIC_6, + Slot::MAGIC_7, + Slot::MAGIC_8}; + + for (Slot s : possibleSlots) + { + if (!getItemInSlot(s).isValid()) + return s; + } + + return tl::nullopt; +} + +tl::optional CharacterEquipment::findAnyFreeRingSlot() const +{ + Slot possibleSlots[] = { + Slot::RING_LEFT, + Slot::RING_RIGHT, + }; + + for (Slot s : possibleSlots) + { + if (!getItemInSlot(s).isValid()) + return s; + } + + return tl::nullopt; +} + +bool CharacterEquipment::hasMeleeWeaponEquipped() const +{ + return getItemInSlot(Slot::MELEE).isValid(); +} + +bool CharacterEquipment::hasBowEquipped() const +{ + return getItemInSlot(Slot::BOW).isValid(); +} + +bool Logic::CharacterEquipment::hasItemEquipped(ItemHandle item) const +{ + for(auto h: m_ItemsBySlot) + { + if(h == item) + return true; + } + + return false; +} + +bool CharacterEquipment::isItemTypeCorrectForSlot(ItemHandle item, Slot slot) const +{ + Kind kind = getKindOfItem(item); + + switch (kind) + { + case Kind::MELEE: + return slot == Slot::MELEE; + + case Kind::BOW: + return slot == Slot::BOW; + + case Kind::AMULET: + return slot == Slot::AMULET; + + case Kind::RING: + { + if (slot == Slot::RING_LEFT) + return true; + + if (slot == Slot::RING_RIGHT) + return true; + + return false; + } + + case Kind::MAGIC: + { + Slot possibleSlots[] = { + Slot::MAGIC_0, + Slot::MAGIC_1, + Slot::MAGIC_2, + Slot::MAGIC_3, + Slot::MAGIC_4, + Slot::MAGIC_5, + Slot::MAGIC_6, + Slot::MAGIC_7, + Slot::MAGIC_8}; + + for (Slot s : possibleSlots) + { + if (slot == s) + return true; + } + + return false; + } + + case Kind::BELT: + return slot == Slot::BELT; + + case Kind::OTHER: + default: + return false; + } +} + +bool CharacterEquipment::doAttributesAllowUse(ItemHandle item) const +{ + // Check attributes + Daedalus::GEngineClasses::C_Item& data = m_World.getScriptEngine().getGameState().getItem(item); + Daedalus::GEngineClasses::C_Npc& npc = getController().getScriptInstance(); + ScriptEngine& s = m_World.getScriptEngine(); + + for (size_t i = 0; i < Daedalus::GEngineClasses::C_Item::COND_ATR_MAX; i++) + { + // Why is 0 not allowed? That's how gothic is doing it though, as it seems... + if (data.cond_atr[i] > 0) + { + assert(data.cond_atr[i] < Daedalus::GEngineClasses::C_Npc::EATR_MAX); + + // Check for enough strength, etc. + if (npc.attribute[data.cond_atr[i]] < data.cond_value[i]) + { + return false; + } + } + } + + return true; +} + +tl::optional CharacterEquipment::getItemDataInSlot(Slot slot) const +{ + return getDataOfItem(getItemInSlot(slot)); +} + +CharacterEquipment::ItemHandle CharacterEquipment::getItemInSlot(Slot slot) const +{ + return m_ItemsBySlot[(size_t)slot]; +} + +void Logic::CharacterEquipment::setItemInSlot(ItemHandle item, Slot slot) +{ + m_ItemsBySlot[(size_t)slot] = item; +} + +PlayerController& CharacterEquipment::getController() const +{ + auto logic = m_World.getEntity(m_CharacterEntity).m_pLogicController; + assert(logic != nullptr); + return *reinterpret_cast(logic); +} + +tl::optional Logic::CharacterEquipment::getDataOfItem(ItemHandle item) const +{ + if (!item.isValid()) + return tl::nullopt; + + return m_World.getScriptEngine().getGameState().getItem(item); +} diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h new file mode 100644 index 00000000..cbf01600 --- /dev/null +++ b/src/logic/CharacterEquipment.h @@ -0,0 +1,160 @@ +// +// Created by andre on 28.06.18. +// + +#pragma once + +#include +#include +#include +#include + +namespace World +{ + class WorldInstance; +} + +namespace Logic +{ + class PlayerController; + /** + * Contains information about what a character currently has equipped. + * This encapsulates logic like whether the characters attributes are high enough + * and how many rings can be worn at once. + */ + class CharacterEquipment + { + public: + using ItemHandle = Daedalus::GameState::ItemHandle; + using ItemData = Daedalus::GEngineClasses::C_Item; + + enum class Slot : size_t + { + MELEE, + BOW, // + Crossbow + MAGIC_0, + MAGIC_1, + MAGIC_2, + MAGIC_3, + MAGIC_4, + MAGIC_5, + MAGIC_6, + MAGIC_7, + MAGIC_8, + MAGIC_9, + RING_LEFT, + RING_RIGHT, + AMULET, + BELT, + COUNT, + }; + + enum class Kind : size_t + { + MELEE, + BOW, + AMULET, + RING, + MAGIC, + BELT, + OTHER, + }; + + CharacterEquipment(World::WorldInstance& world, Handle::EntityHandle characterEntity); + + /** + * Tries to equip the given item to the given slot. + * Returns true on success. + * Returns false if not possible (attributes, wrong kind of slot). + */ + bool equipItemToSlot(ItemHandle item, Slot slot); + + /** + * Finds a slot the given item could potentially be equipped to. + * For magic and rings the first slot is returned, regardless of + * whether it's empty or not. + * This function also does not check whether the attributes of the + * underlaying character allow equipment. + */ + tl::optional getCorrectSlotForItem(ItemHandle item) const; + + /** + * Figures out which kind of item the given handle represents. + * Every kind except "OTHER" can be equipped. + */ + Kind getKindOfItem(ItemHandle item) const; + + /** + * Some types of items can be equipped to multiple slots. These functions + * return the first free one they can find. + */ + tl::optional findAnyFreeMagicSlot() const; + tl::optional findAnyFreeRingSlot() const; + + /** + * Status queries + */ + bool hasMeleeWeaponEquipped() const; + bool hasBowEquipped() const; + bool hasItemEquipped(ItemHandle item) const; + + /** + * Whether the given item could be equipped into the given slot. + * Ie. A ring cannot be equipped to the slot meant for melee-weapons. + */ + bool isItemTypeCorrectForSlot(ItemHandle item, Slot slot) const; + + /** + * Whether the underlaying characters attributes are high enough to + * equip or use the given item. + * + * This can also be called on non-equipable items such as food where it makes sense! + */ + bool doAttributesAllowUse(ItemHandle item) const; + + /** + * @return the item currently equipped in the slot + */ + tl::optional getItemDataInSlot(Slot slot) const; + ItemHandle getItemInSlot(Slot slot) const; + + protected: + + /** + * Assigns the given item to the given slot without any checks + * or anything else + */ + void setItemInSlot(ItemHandle item, Slot slot); + + std::array m_ItemsBySlot; + + /** + * These functions perform the actual equipment. + * For these functions to succeed, the target slot needs to be + * empty! + * + * @return True, if equipping was possible + * False otherwise (ie. attributes too low) + */ + bool equipMelee(ItemHandle item); + bool equipBow(ItemHandle item); + bool equipAmulet(ItemHandle item); + bool equipRing(ItemHandle item, Slot slot); + bool equipMagic(ItemHandle item, Slot slot); + bool equipBelt(ItemHandle item); + + /** + * @return handle to the underlaying character + */ + PlayerController& getController() const; + + /** + * @return Data of the given item + */ + tl::optional getDataOfItem(ItemHandle item) const; + + World::WorldInstance& m_World; + Handle::EntityHandle m_CharacterEntity; + }; + +} // namespace Logic From cb1c37186b27f99aca725dab495c45110dfa343d Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:32:14 +0200 Subject: [PATCH 16/36] CharacterEquipment: Add methods to check whether an item is of a specific kind or equippable --- src/logic/CharacterEquipment.cpp | 14 ++++++++++++-- src/logic/CharacterEquipment.h | 10 ++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index d36e1972..46641bd4 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -196,9 +196,9 @@ bool CharacterEquipment::hasBowEquipped() const bool Logic::CharacterEquipment::hasItemEquipped(ItemHandle item) const { - for(auto h: m_ItemsBySlot) + for (auto h : m_ItemsBySlot) { - if(h == item) + if (h == item) return true; } @@ -262,6 +262,16 @@ bool CharacterEquipment::isItemTypeCorrectForSlot(ItemHandle item, Slot slot) co } } +bool Logic::CharacterEquipment::isItemOfKind(ItemHandle item, Kind kind) const +{ + return getKindOfItem(item) == kind; +} + +bool Logic::CharacterEquipment::isItemEquipable(ItemHandle item) const +{ + return !isItemOfKind(item, Kind::OTHER); // All but OTHER can be equipped +} + bool CharacterEquipment::doAttributesAllowUse(ItemHandle item) const { // Check attributes diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index cbf01600..452ba2fa 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -104,6 +104,16 @@ namespace Logic */ bool isItemTypeCorrectForSlot(ItemHandle item, Slot slot) const; + /** + * @return Whether the given item is of the given kind + */ + bool isItemOfKind(ItemHandle item, Kind kind) const; + + /** + * @return Whether this item is possible equippable (not checking attributes) + */ + bool isItemEquipable(ItemHandle item) const; + /** * Whether the underlaying characters attributes are high enough to * equip or use the given item. From 0ec090b5c704e290e995110af89121e813acc132 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:38:26 +0200 Subject: [PATCH 17/36] CharacterEquipment: Add Armor --- src/logic/CharacterEquipment.cpp | 21 +++++++++++++++++++-- src/logic/CharacterEquipment.h | 3 +++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 46641bd4..ac123c23 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -40,6 +40,9 @@ bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) case Kind::BELT: return equipBelt(item); + case Kind::ARMOR: + return equipArmor(item); + case Kind::OTHER: default: return false; @@ -84,6 +87,12 @@ bool Logic::CharacterEquipment::equipBelt(ItemHandle item) return true; } +bool Logic::CharacterEquipment::equipArmor(ItemHandle item) +{ + setItemInSlot(item, Slot::ARMOR); + return true; +} + tl::optional CharacterEquipment::getCorrectSlotForItem(ItemHandle item) const { switch (getKindOfItem(item)) @@ -98,6 +107,8 @@ tl::optional CharacterEquipment::getCorrectSlotForItem return Slot::RING_LEFT; case Kind::MAGIC: return Slot::MAGIC_0; + case Kind::ARMOR: + return Slot::ARMOR; case Kind::BELT: return Slot::BELT; case Kind::OTHER: @@ -116,13 +127,16 @@ CharacterEquipment::Kind CharacterEquipment::getKindOfItem(ItemHandle item) cons auto& itemData = *itemDataOpt; - // Magic can only be identified through the mainflags + // Magic and armor can only be identified through the mainflags if ((itemData.mainflag & C_Item::ITM_CAT_RUNE) != 0) return Kind::MAGIC; if ((itemData.mainflag & C_Item::ITM_CAT_MAGIC) != 0) return Kind::MAGIC; + if ((itemData.mainflag & C_Item::ITM_CAT_ARMOR) != 0) + return Kind::ARMOR; + std::pair pairs[] = { {C_Item::Flags::ITEM_DAG, Kind::MELEE}, {C_Item::Flags::ITEM_SWD, Kind::MELEE}, @@ -256,6 +270,9 @@ bool CharacterEquipment::isItemTypeCorrectForSlot(ItemHandle item, Slot slot) co case Kind::BELT: return slot == Slot::BELT; + case Kind::ARMOR: + return slot == Slot::ARMOR; + case Kind::OTHER: default: return false; @@ -269,7 +286,7 @@ bool Logic::CharacterEquipment::isItemOfKind(ItemHandle item, Kind kind) const bool Logic::CharacterEquipment::isItemEquipable(ItemHandle item) const { - return !isItemOfKind(item, Kind::OTHER); // All but OTHER can be equipped + return !isItemOfKind(item, Kind::OTHER); // All but OTHER can be equipped } bool CharacterEquipment::doAttributesAllowUse(ItemHandle item) const diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index 452ba2fa..441b39df 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -46,6 +46,7 @@ namespace Logic RING_RIGHT, AMULET, BELT, + ARMOR, COUNT, }; @@ -57,6 +58,7 @@ namespace Logic RING, MAGIC, BELT, + ARMOR, OTHER, }; @@ -152,6 +154,7 @@ namespace Logic bool equipRing(ItemHandle item, Slot slot); bool equipMagic(ItemHandle item, Slot slot); bool equipBelt(ItemHandle item); + bool equipArmor(ItemHandle item); /** * @return handle to the underlaying character From 69afa0f3cc56f97d18e815273c510b588c495ccb Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:41:09 +0200 Subject: [PATCH 18/36] PlayerController: Run clang-format --- src/logic/PlayerController.cpp | 131 ++++++++++++++++----------------- src/logic/PlayerController.h | 11 ++- 2 files changed, 68 insertions(+), 74 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 85173307..511cf08c 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -17,21 +17,19 @@ #include #include #include +#include #include +#include +#include #include +#include +#include +#include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include - #define DEBUG_PLAYER (isPlayerControlled() && false) @@ -59,12 +57,12 @@ namespace BodyNodes const char* NPC_NODE_HELMET = "ZS_HELMET"; const char* NPC_NODE_JAWS = "ZS_JAWS"; const char* NPC_NODE_TORSO = "ZS_TORSO"; -} +} // namespace BodyNodes /** * Default soundrange for SFX which doesn't specify a range. Gothic uses a default value of 35 meters. */ -static const float DEFAULT_CHARACTER_SOUND_RANGE = 35; // Meters +static const float DEFAULT_CHARACTER_SOUND_RANGE = 35; // Meters #define SINGLE_ACTION_KEY(key, fn) \ { \ @@ -180,7 +178,8 @@ void PlayerController::onUpdate(float deltaTime) if (isPlayerControlled()) { onUpdateForPlayer(deltaTime); - }else + } + else { m_AIHandler.npcUpdate(deltaTime); } @@ -208,13 +207,11 @@ void PlayerController::teleportToPosition(const Math::float3& pos) //getModelVisual()->setAnimation(ModelVisual::Idle); } - void PlayerController::gotoWaypoint(World::Waynet::WaypointIndex wp) { m_PathFinder.startNewRouteTo(getEntityTransform().Translation(), wp); } - void PlayerController::gotoVob(Handle::EntityHandle vob) { m_PathFinder.startNewRouteTo(getEntityTransform().Translation(), vob); @@ -231,7 +228,7 @@ void PlayerController::travelPath() Pathfinder::Instruction inst = m_PathFinder.updateToNextInstructionToTarget(positionNow); - if(!m_PathFinder.isTargetReachedByPosition(positionNow, inst.targetPosition)) + if (!m_PathFinder.isTargetReachedByPosition(positionNow, inst.targetPosition)) { // Turn towards target setDirection(inst.targetPosition - positionNow); @@ -241,7 +238,6 @@ void PlayerController::travelPath() m_AIHandler.setTargetMovementState(EMovementState::Forward); } - void PlayerController::onDebugDraw() { if (isPlayerControlled()) @@ -765,7 +761,6 @@ void PlayerController::onUpdateByInput(float deltaTime) m_AIHandler.playerUpdate(deltaTime); } - void PlayerController::onMessage(SharedEMessage message, Handle::EntityHandle sourceVob) { Controller::onMessage(message, sourceVob); @@ -844,7 +839,7 @@ bool PlayerController::EV_Movement(std::shared_ptrfindNodeIndex(e.bodyPosition); auto position = transform * boneTransforms[nodeIndex]; Vob::setTransform(vob, std::move(position)); @@ -2021,9 +2016,9 @@ void PlayerController::updatePfxPosition(const pfxEvent &e) void PlayerController::updatePfx() { //First remove all invalid handles / emitter that are in "canBeRemoved" state (all particles are dead) - for(auto it = m_activePfxEvents.begin(); itcanBeRemoved()) + if (((PfxVisual*)Vob::asVob(m_World, (*it).entity).visual)->canBeRemoved()) { m_World.removeEntity((*it).entity); it = m_activePfxEvents.erase(it); @@ -2031,7 +2026,7 @@ void PlayerController::updatePfx() else { //If pfx is attached to body, update the position - if((*it).isAttached) + if ((*it).isAttached) updatePfxPosition(*it); ++it; @@ -2070,7 +2065,7 @@ void PlayerController::AniEvent_SFX(const ZenLoad::zCModelScriptEventSfx& sfx) } } - if(!sfx.m_EmptySlot && m_World.getAudioWorld().soundIsPlaying(m_MainNoiseSoundSlot)) + if (!sfx.m_EmptySlot && m_World.getAudioWorld().soundIsPlaying(m_MainNoiseSoundSlot)) { // If emptyslot is not set, the currently played sound shall be stopped m_World.getAudioWorld().stopSound(m_MainNoiseSoundSlot); @@ -2081,11 +2076,11 @@ void PlayerController::AniEvent_SFX(const ZenLoad::zCModelScriptEventSfx& sfx) auto ticket = m_World.getAudioWorld().playSound(sfx.m_Name, getEntityTransform().Translation(), range); - if(!sfx.m_EmptySlot) + if (!sfx.m_EmptySlot) { // If emptyslot is not set, the currently played sound shall be stopped - if(m_World.getAudioWorld().soundIsPlaying(m_MainNoiseSoundSlot)) + if (m_World.getAudioWorld().soundIsPlaying(m_MainNoiseSoundSlot)) m_World.getAudioWorld().stopSound(m_MainNoiseSoundSlot); m_MainNoiseSoundSlot = ticket; @@ -2105,11 +2100,11 @@ void PlayerController::AniEvent_SFXGround(const ZenLoad::zCModelScriptEventSfx& auto ticket = m_World.getAudioWorld().playSoundVariantRandom(soundfile, getEntityTransform().Translation(), range); - if(!sfx.m_EmptySlot) + if (!sfx.m_EmptySlot) { // If emptyslot is not set, the currently played sound shall be stopped - if(m_World.getAudioWorld().soundIsPlaying(m_MainNoiseSoundSlot)) + if (m_World.getAudioWorld().soundIsPlaying(m_MainNoiseSoundSlot)) m_World.getAudioWorld().stopSound(m_MainNoiseSoundSlot); m_MainNoiseSoundSlot = ticket; @@ -2123,41 +2118,42 @@ void PlayerController::AniEvent_Tag(const ZenLoad::zCModelScriptEventTag& tag) } void PlayerController::AniEvent_PFX(const ZenLoad::zCModelScriptEventPfx& pfx) { - if(!m_World.getPfxManager().hasPFX(pfx.m_Name)) + if (!m_World.getPfxManager().hasPFX(pfx.m_Name)) { return; } pfxEvent event = {Vob::constructVob(m_World), pfx.m_Pos, pfx.m_isAttached, pfx.m_Num}; //From world of gothic animation events - if(event.bodyPosition.empty()) + if (event.bodyPosition.empty()) { event.bodyPosition = "BIP01"; } m_activePfxEvents.push_back(std::move(event)); Vob::VobInformation vob = Vob::asVob(m_World, m_activePfxEvents.back().entity); - Vob::setVisual(vob, pfx.m_Name+".PFX"); - Vob::setTransform(vob, getEntityTransform()); + Vob::setVisual(vob, pfx.m_Name + ".PFX"); + Vob::setTransform(vob, getEntityTransform()); } void PlayerController::AniEvent_PFXStop(const ZenLoad::zCModelScriptEventPfxStop& pfxStop) { - //FIXME there is the error (at icedragon at oldworld) that there are pfxStop Events when no active pfx events are present... - if(m_activePfxEvents.empty()) - LogWarn() << "No corresponding pfx Event for Stop Event of Animation " + getNpcAnimationHandler().getAnimHandler().getActiveAnimationPtr()->m_Name; + //FIXME there is the error (at icedragon at oldworld) that there are pfxStop Events when no active pfx events are present... + if (m_activePfxEvents.empty()) + LogWarn() << "No corresponding pfx Event for Stop Event of Animation " + getNpcAnimationHandler().getAnimHandler().getActiveAnimationPtr()->m_Name; //Kill pfx with the corresponding number - for (auto &pfx : m_activePfxEvents) { - if (pfx.m_Num == pfxStop.m_Num) { - Vob::VobInformation vob = Vob::asVob(m_World, pfx.entity); - PfxVisual *visual = (PfxVisual *) vob.visual; - if (visual->isDead()) { - continue; - } - visual->killPfx(); - break; - } - } - - + for (auto& pfx : m_activePfxEvents) + { + if (pfx.m_Num == pfxStop.m_Num) + { + Vob::VobInformation vob = Vob::asVob(m_World, pfx.entity); + PfxVisual* visual = (PfxVisual*)vob.visual; + if (visual->isDead()) + { + continue; + } + visual->killPfx(); + break; + } + } } World::Waynet::WaypointIndex PlayerController::getClosestWaypoint() @@ -2187,7 +2183,7 @@ World::Waynet::WaypointIndex PlayerController::getSecondClosestWaypoint() float l2 = (position - waynet.waypoints[i].position).lengthSquared(); distances.emplace_back(l2, i); } - auto compare = [](const auto& pair1, const auto& pair2){ + auto compare = [](const auto& pair1, const auto& pair2) { return pair1.first < pair2.first; }; std::nth_element(distances.begin(), distances.begin() + 1, distances.end(), compare); @@ -2219,7 +2215,7 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f } } } - break; + break; case ActionType::PlayerBackward: { // Increment state, if currently using a mob @@ -2237,7 +2233,7 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f } } } - break; + break; case ActionType::DebugMoveSpeed: m_MoveSpeed1 = m_MoveSpeed1 || triggered; @@ -2248,11 +2244,11 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f case ActionType::PlayerRotate: { auto dir = getDirection(); - auto deltaPhi = 0.02f * intensity; // TODO window width influences this??? + auto deltaPhi = 0.02f * intensity; // TODO window width influences this??? dir = Math::Matrix::rotatedPointAroundLine(dir, {0, 0, 0}, getEntityTransform().Up(), deltaPhi); setDirection(dir); } - break; + break; case ActionType::PlayerAction: { if (triggered) @@ -2272,8 +2268,8 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f Math::Matrix& m = m_World.getEntity(h).m_WorldMatrix; float dist = (m.Translation() - - getEntityTransform().Translation()) - .lengthSquared(); + getEntityTransform().Translation()) + .lengthSquared(); if (dist < shortestDistItem && dist < 10.0f * 10.0f) { nearestItem = h; @@ -2294,8 +2290,8 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f VobTypes::NpcVobInformation npc = VobTypes::asNpcVob(m_World, h); float dist = (Vob::getTransform(npc).Translation() - - getEntityTransform().Translation()) - .lengthSquared(); + getEntityTransform().Translation()) + .lengthSquared(); if (dist < shortestDistNPC) { nearestNPC = h; @@ -2314,8 +2310,8 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f VobTypes::MobVobInformation vob = VobTypes::asMobVob(m_World, h); float dist = (Vob::getTransform(vob).Translation() - - getEntityTransform().Translation()) - .lengthSquared(); + getEntityTransform().Translation()) + .lengthSquared(); if (dist < shortestDistMob) { @@ -2405,8 +2401,7 @@ void PlayerController::onAction(Engine::ActionType actionType, bool triggered, f } } } - break; - + break; case ActionType::PlayerActionContinous: break; diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 6d7bacc3..fb6decd6 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -39,7 +39,7 @@ namespace Logic const char* const PLAYER_MOB_ANOTHER_IS_USING = "PLAYER_MOB_ANOTHER_IS_USING"; const char* const PLAYER_PLUNDER_IS_EMPTY = "PLAYER_PLUNDER_IS_EMPTY"; const char* const PLAYER_RANGED_NO_AMMO = "PLAYER_RANGED_NO_AMMO"; - } + } // namespace PlayerScriptInfo /** * All kinds of things an NPC can do @@ -83,7 +83,6 @@ namespace Logic class PlayerController : public Controller { public: - using WalkMode = EventMessages::MovementMessage::WalkMode; /** @@ -539,7 +538,7 @@ namespace Logic Daedalus::GameState::ItemHandle equippedAmulet; } equippedItems; } m_EquipmentState; - + Inventory m_Inventory; NpcScriptState m_AIStateMachine; NpcAnimationHandler m_NPCAnimationHandler; @@ -564,7 +563,7 @@ namespace Logic Handle::EntityHandle entity; std::string bodyPosition; bool isAttached; - int32_t m_Num; + int32_t m_Num; }; /** @@ -582,7 +581,7 @@ namespace Logic * Updates the position of the pfxEvent * @param e pfxEvent */ - void updatePfxPosition(const pfxEvent &e); + void updatePfxPosition(const pfxEvent& e); /** * Upates the pfx for this player (removes dead emitter) @@ -600,4 +599,4 @@ namespace Logic // Main noise sound slot. Other sounds using it won't play if there is already a sound playing here. Utils::Ticket m_MainNoiseSoundSlot; }; -} +} // namespace Logic From b2ae4777ae3401726d2e7235f36fceee8c7b7f9f Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:42:42 +0200 Subject: [PATCH 19/36] PlayerController: Instantiate CharacterEquipment --- src/logic/PlayerController.cpp | 1 + src/logic/PlayerController.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 511cf08c..ee7e3a0d 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -85,6 +85,7 @@ PlayerController::PlayerController(World::WorldInstance& world, , m_NPCAnimationHandler(world, entity) , m_AIHandler(world, entity) , m_PathFinder(world) + , m_CharacterEquipment(world, entity) { m_AIState.closestWaypoint = 0; m_NPCProperties.enablePhysics = true; diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index fb6decd6..e503b601 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -8,6 +8,7 @@ #include "NpcAnimationHandler.h" #include "NpcScriptState.h" #include "Pathfinder.h" +#include "CharacterEquipment.h" #include namespace UI @@ -544,6 +545,7 @@ namespace Logic NpcAnimationHandler m_NPCAnimationHandler; NpcAIHandler m_AIHandler; Pathfinder m_PathFinder; + CharacterEquipment m_CharacterEquipment; /** * refuse talk countdown From ec1646e38259f732375cfd9a776fec043e9d2159 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:45:34 +0200 Subject: [PATCH 20/36] PlayerController: Refractor check whether an item can be equipped --- src/logic/PlayerController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index ee7e3a0d..010b99e3 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -1484,8 +1484,8 @@ bool PlayerController::useItem(Daedalus::GameState::ItemHandle item) changeAttribute(Daedalus::GEngineClasses::C_Npc::EATR_HITPOINTS, data.nutrition); } - // Weapon? - if ((data.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_NF) != 0 || (data.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_FF) != 0 || (data.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_ARMOR) != 0 || (data.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_MAGIC) != 0) + // Equipment? + if (m_CharacterEquipment.isItemEquipable(item)) { // FIXME: Hack to only allow equipping when no weapon is drawn if (getWeaponMode() == EWeaponMode::WeaponNone) From 7dea4e5ef81f4996ff79d35be614b6576ba8f086 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 01:48:50 +0200 Subject: [PATCH 21/36] CharacterEquipment: Respect "ITM_CAT_EQUIPABLE" when getting the item-kind --- src/logic/CharacterEquipment.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index ac123c23..07a2efd0 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -127,6 +127,10 @@ CharacterEquipment::Kind CharacterEquipment::getKindOfItem(ItemHandle item) cons auto& itemData = *itemDataOpt; + // Only equippable items get a kind + if ((itemData.mainflag & C_Item::ITM_CAT_EQUIPABLE) == 0) + return Kind::OTHER; + // Magic and armor can only be identified through the mainflags if ((itemData.mainflag & C_Item::ITM_CAT_RUNE) != 0) return Kind::MAGIC; From 281e0559fe9371a71be666438ae33b746d00c36a Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 02:34:50 +0200 Subject: [PATCH 22/36] PlayerController: Refactored equipable-check once more --- src/logic/PlayerController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 010b99e3..9d1678f6 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -374,7 +374,7 @@ void PlayerController::equipItem(Daedalus::GameState::ItemHandle item) Daedalus::GEngineClasses::C_Item& itemData = m_World.getScriptEngine().getGameState().getItem(item); ModelVisual* model = getModelVisual(); - if ((itemData.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_EQUIPABLE) == 0) + if (!m_CharacterEquipment.isItemEquipable(item)) return; // Can't equip EModelNode node = EModelNode::None; From 5b1095a0023d8e8d2ba89f01b61f44a30196f141 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 02:35:12 +0200 Subject: [PATCH 23/36] CharacterEquipment: Add code to set model attachments and armor visual --- src/logic/CharacterEquipment.cpp | 136 +++++++++++++++++++++++++++++++ src/logic/CharacterEquipment.h | 28 +++++++ 2 files changed, 164 insertions(+) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 07a2efd0..1b6484c6 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -51,15 +51,93 @@ bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) return true; } +void Logic::CharacterEquipment::unequipItemInSlot(Slot slot) +{ + switch (slot) + { + case Slot::MELEE: + removeCharacterModelAttachment(EModelNode::Longsword); + removeCharacterModelAttachment(EModelNode::Sword); + break; + + case Slot::BOW: + removeCharacterModelAttachment(EModelNode::Bow); + removeCharacterModelAttachment(EModelNode::Crossbow); + break; + + case Slot::ARMOR: + switchToDefaultCharacterModel(); + break; + + default: // Everything else can be taken off without visual changes + break; + } +} + bool Logic::CharacterEquipment::equipMelee(ItemHandle item) { + using Daedalus::GEngineClasses::C_Item; + + auto data = getDataOfItem(item); + + if (!data) + return false; + + EModelNode node; + if (data->flags & C_Item::Flags::ITEM_2HD_AXE) + { + node = EModelNode::Longsword; + } + else if (data->flags & C_Item::Flags::ITEM_2HD_SWD) + { + node = EModelNode::Longsword; + } + else if (data->flags & C_Item::Flags::ITEM_AXE) + { + node = EModelNode::Sword; + } + else if (data->flags & C_Item::Flags::ITEM_SWD) + { + node = EModelNode::Sword; + } + else + { + // What is this? + return false; + } + + setCharacterModelAttachment(getItemVisual(item), node); + setItemInSlot(item, Slot::MELEE); + return true; } bool Logic::CharacterEquipment::equipBow(ItemHandle item) { + using Daedalus::GEngineClasses::C_Item; + + auto data = getDataOfItem(item); + + if (!data) + return false; + + if (data->flags & C_Item::Flags::ITEM_CROSSBOW) + { + setCharacterModelAttachment(getItemVisual(item), EModelNode::Crossbow); + } + else if (data->flags & C_Item::Flags::ITEM_BOW) + { + setCharacterModelAttachment(getItemVisual(item), EModelNode::Bow); + } + else + { + // What is this? + return false; + } + setItemInSlot(item, Slot::BOW); + return true; } @@ -89,6 +167,14 @@ bool Logic::CharacterEquipment::equipBelt(ItemHandle item) bool Logic::CharacterEquipment::equipArmor(ItemHandle item) { + using Daedalus::GEngineClasses::C_Item; + + auto data = getDataOfItem(item); + + if (!data) + return false; + + switchCharacterModelArmor(data->visual_change); setItemInSlot(item, Slot::ARMOR); return true; } @@ -323,6 +409,16 @@ tl::optional CharacterEquipment::getItemDataInSlo return getDataOfItem(getItemInSlot(slot)); } +std::string Logic::CharacterEquipment::getItemVisual(ItemHandle item) const +{ + auto data = getDataOfItem(item); + + if (!data) + return ""; + + return data->visual; +} + CharacterEquipment::ItemHandle CharacterEquipment::getItemInSlot(Slot slot) const { return m_ItemsBySlot[(size_t)slot]; @@ -347,3 +443,43 @@ tl::optional Logic::CharacterEquipment::getDataOf return m_World.getScriptEngine().getGameState().getItem(item); } + +void CharacterEquipment::setCharacterModelAttachment(const std::string& visual, EModelNode node) +{ + ModelVisual* pVisual = getController().getModelVisual(); + + if (!pVisual) + return; + + pVisual->setNodeVisual(visual, node); +} + +void Logic::CharacterEquipment::removeCharacterModelAttachment(EModelNode node) +{ + setCharacterModelAttachment("", node); +} + +void Logic::CharacterEquipment::switchToDefaultCharacterModel() +{ + ModelVisual* pVisual = getController().getModelVisual(); + + if (!pVisual) + return; + + // TODO: Implement this. Actually not easy to get the default character model as it seems + // ModelVisual::BodyState state = pVisual->getBodyState(); + // state.bodyVisual = getController().getScriptInstance(). +} + +void CharacterEquipment::switchCharacterModelArmor(const std::string& visual) +{ + ModelVisual* pVisual = getController().getModelVisual(); + + if (!pVisual) + return; + + ModelVisual::BodyState state = pVisual->getBodyState(); + state.bodyVisual = visual; + + pVisual->setBodyState(state); +} diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index 441b39df..765d2afa 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace World { @@ -71,6 +72,11 @@ namespace Logic */ bool equipItemToSlot(ItemHandle item, Slot slot); + /** + * Takes of the item currently in the given slot + */ + void unequipItemInSlot(Slot slot); + /** * Finds a slot the given item could potentially be equipped to. * For magic and rings the first slot is returned, regardless of @@ -156,6 +162,22 @@ namespace Logic bool equipBelt(ItemHandle item); bool equipArmor(ItemHandle item); + /** + * Sets the visual attachment on the character model + */ + void setCharacterModelAttachment(const std::string& visual, EModelNode node); + void removeCharacterModelAttachment(EModelNode node); + + /** + * Switches to the default no-armor body mesh + */ + void switchToDefaultCharacterModel(); + + /** + * Switches to the given armor-visual + */ + void switchCharacterModelArmor(const std::string& visual); + /** * @return handle to the underlaying character */ @@ -166,6 +188,12 @@ namespace Logic */ tl::optional getDataOfItem(ItemHandle item) const; + + /** + * @return The visual for this item set by the scripts + */ + std::string getItemVisual(ItemHandle item) const; + World::WorldInstance& m_World; Handle::EntityHandle m_CharacterEntity; }; From 0bcb5fcb7e175b84730a660218940b85fd12515f Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 02:44:17 +0200 Subject: [PATCH 24/36] CharacterEquipment: Add function to equip an item to any valid free slot --- src/logic/CharacterEquipment.cpp | 32 ++++++++++++++++++++++++++++++++ src/logic/CharacterEquipment.h | 7 +++++++ 2 files changed, 39 insertions(+) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 1b6484c6..2f961730 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -51,6 +51,38 @@ bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) return true; } +bool Logic::CharacterEquipment::equipItem(ItemHandle item) +{ + tl::optional slot; + switch (getKindOfItem(item)) + { + case Kind::MELEE: + case Kind::BOW: + case Kind::AMULET: + case Kind::BELT: + case Kind::ARMOR: + slot = getCorrectSlotForItem(item); + break; + + case Kind::RING: + slot = findAnyFreeRingSlot(); + break; + + case Kind::MAGIC: + slot = findAnyFreeMagicSlot(); + break; + + case Kind::OTHER: + default: + return false; + } + + if (!slot) + return false; + + return equipItemToSlot(item, *slot); +} + void Logic::CharacterEquipment::unequipItemInSlot(Slot slot) { switch (slot) diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index 765d2afa..cc66b958 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -72,6 +72,13 @@ namespace Logic */ bool equipItemToSlot(ItemHandle item, Slot slot); + /** + * Equips the item to any free slot avilable for it. + * @return True, if a slot has been found and the item could be equipped + * False, if all possible slots are full or the attributes aren't correct + */ + bool equipItem(ItemHandle item); + /** * Takes of the item currently in the given slot */ From aea4cd100f8c940c7c1c3a479a96f9d5f722fd58 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 02:51:50 +0200 Subject: [PATCH 25/36] CharacterEquipment: Add functions to unequip items --- src/logic/CharacterEquipment.cpp | 27 +++++++++++++++++++++++++++ src/logic/CharacterEquipment.h | 10 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 2f961730..f1ee7a87 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -17,6 +17,9 @@ CharacterEquipment::CharacterEquipment(World::WorldInstance& world, Handle::Enti bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) { + if (!isItemEquipable(item)) + return false; + if (!isItemTypeCorrectForSlot(item, slot)) return false; @@ -53,6 +56,9 @@ bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) bool Logic::CharacterEquipment::equipItem(ItemHandle item) { + if (!isItemEquipable(item)) + return false; + tl::optional slot; switch (getKindOfItem(item)) { @@ -106,6 +112,16 @@ void Logic::CharacterEquipment::unequipItemInSlot(Slot slot) } } +void Logic::CharacterEquipment::unequipItem(ItemHandle item) +{ + auto slot = findSlotItemWasEquippedTo(item); + + if(slot) + { + unequipItemInSlot(*slot); + } +} + bool Logic::CharacterEquipment::equipMelee(ItemHandle item) { using Daedalus::GEngineClasses::C_Item; @@ -320,6 +336,17 @@ tl::optional CharacterEquipment::findAnyFreeRingSlot() return tl::nullopt; } +tl::optional CharacterEquipment::findSlotItemWasEquippedTo(ItemHandle item) const +{ + for(size_t i = 0; i < (size_t)Slot::COUNT; i++) + { + if (m_ItemsBySlot[i] == item) + return (Slot)i; + } + + return tl::nullopt; +} + bool CharacterEquipment::hasMeleeWeaponEquipped() const { return getItemInSlot(Slot::MELEE).isValid(); diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index cc66b958..0cd338d9 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -84,6 +84,11 @@ namespace Logic */ void unequipItemInSlot(Slot slot); + /** + * Unequips the given item, if it is currently equipped + */ + void unequipItem(ItemHandle item); + /** * Finds a slot the given item could potentially be equipped to. * For magic and rings the first slot is returned, regardless of @@ -106,6 +111,11 @@ namespace Logic tl::optional findAnyFreeMagicSlot() const; tl::optional findAnyFreeRingSlot() const; + /** + * Finds the slot the given item was equipped to + */ + tl::optional findSlotItemWasEquippedTo(ItemHandle item) const; + /** * Status queries */ From 896cb6d49826b9f6ce526c309b26433b7a79a000 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 03:06:40 +0200 Subject: [PATCH 26/36] CharacterEquipment: Add functions to put items into the characters hands --- src/logic/CharacterEquipment.cpp | 113 +++++++++++++++++++------------ src/logic/CharacterEquipment.h | 15 ++++ 2 files changed, 86 insertions(+), 42 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index f1ee7a87..bea8290e 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -116,13 +116,53 @@ void Logic::CharacterEquipment::unequipItem(ItemHandle item) { auto slot = findSlotItemWasEquippedTo(item); - if(slot) + if (slot) { unequipItemInSlot(*slot); } } bool Logic::CharacterEquipment::equipMelee(ItemHandle item) +{ + setItemInSlot(item, Slot::MELEE); + + return true; +} + +bool Logic::CharacterEquipment::equipBow(ItemHandle item) +{ + using Daedalus::GEngineClasses::C_Item; + + setItemInSlot(item, Slot::BOW); + + return true; +} + +bool Logic::CharacterEquipment::equipAmulet(ItemHandle item) +{ + setItemInSlot(item, Slot::AMULET); + return true; +} + +bool Logic::CharacterEquipment::equipRing(ItemHandle item, Slot slot) +{ + setItemInSlot(item, slot); + return true; +} + +bool Logic::CharacterEquipment::equipMagic(ItemHandle item, Slot slot) +{ + setItemInSlot(item, slot); + return true; +} + +bool Logic::CharacterEquipment::equipBelt(ItemHandle item) +{ + setItemInSlot(item, Slot::BELT); + return true; +} + +bool Logic::CharacterEquipment::equipArmor(ItemHandle item) { using Daedalus::GEngineClasses::C_Item; @@ -131,6 +171,21 @@ bool Logic::CharacterEquipment::equipMelee(ItemHandle item) if (!data) return false; + switchCharacterModelArmor(data->visual_change); + setItemInSlot(item, Slot::ARMOR); + return true; +} + +void Logic::CharacterEquipment::showMeleeWeaponOnCharacter() +{ + using Daedalus::GEngineClasses::C_Item; + + auto item = getItemInSlot(Slot::MELEE); + auto data = getDataOfItem(item); + + if (!data) + return; + EModelNode node; if (data->flags & C_Item::Flags::ITEM_2HD_AXE) { @@ -151,24 +206,19 @@ bool Logic::CharacterEquipment::equipMelee(ItemHandle item) else { // What is this? - return false; } setCharacterModelAttachment(getItemVisual(item), node); - - setItemInSlot(item, Slot::MELEE); - - return true; } -bool Logic::CharacterEquipment::equipBow(ItemHandle item) +void Logic::CharacterEquipment::showBowWeaponOnCharacter() { using Daedalus::GEngineClasses::C_Item; - + auto item = getItemInSlot(Slot::BOW); auto data = getDataOfItem(item); if (!data) - return false; + return; if (data->flags & C_Item::Flags::ITEM_CROSSBOW) { @@ -181,50 +231,29 @@ bool Logic::CharacterEquipment::equipBow(ItemHandle item) else { // What is this? - return false; } - - setItemInSlot(item, Slot::BOW); - - return true; } -bool Logic::CharacterEquipment::equipAmulet(ItemHandle item) +void Logic::CharacterEquipment::showMeleeWeaponInCharactersHand() { - setItemInSlot(item, Slot::AMULET); - return true; -} + using Daedalus::GEngineClasses::C_Item; + auto item = getItemInSlot(Slot::MELEE); -bool Logic::CharacterEquipment::equipRing(ItemHandle item, Slot slot) -{ - setItemInSlot(item, slot); - return true; + setCharacterModelAttachment(getItemVisual(item), EModelNode::Righthand); } -bool Logic::CharacterEquipment::equipMagic(ItemHandle item, Slot slot) +void Logic::CharacterEquipment::showBowWeaponOnCharactersHand() { - setItemInSlot(item, slot); - return true; -} + using Daedalus::GEngineClasses::C_Item; + auto item = getItemInSlot(Slot::BOW); -bool Logic::CharacterEquipment::equipBelt(ItemHandle item) -{ - setItemInSlot(item, Slot::BELT); - return true; + setCharacterModelAttachment(getItemVisual(item), EModelNode::Righthand); } -bool Logic::CharacterEquipment::equipArmor(ItemHandle item) +void Logic::CharacterEquipment::removeItemInCharactersHand() { - using Daedalus::GEngineClasses::C_Item; - - auto data = getDataOfItem(item); - - if (!data) - return false; - - switchCharacterModelArmor(data->visual_change); - setItemInSlot(item, Slot::ARMOR); - return true; + removeCharacterModelAttachment(EModelNode::Lefthand); + removeCharacterModelAttachment(EModelNode::Righthand); } tl::optional CharacterEquipment::getCorrectSlotForItem(ItemHandle item) const @@ -338,7 +367,7 @@ tl::optional CharacterEquipment::findAnyFreeRingSlot() tl::optional CharacterEquipment::findSlotItemWasEquippedTo(ItemHandle item) const { - for(size_t i = 0; i < (size_t)Slot::COUNT; i++) + for (size_t i = 0; i < (size_t)Slot::COUNT; i++) { if (m_ItemsBySlot[i] == item) return (Slot)i; diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index 0cd338d9..42dad787 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -179,6 +179,21 @@ namespace Logic bool equipBelt(ItemHandle item); bool equipArmor(ItemHandle item); + /** + * Shows the attachment visuals on the character model for the + * currently equiped items + */ + void showMeleeWeaponOnCharacter(); + void showBowWeaponOnCharacter(); + + /** + * Removes the weapons from the characters body and shows them + * inside their hand + */ + void showMeleeWeaponInCharactersHand(); + void showBowWeaponOnCharactersHand(); + void removeItemInCharactersHand(); + /** * Sets the visual attachment on the character model */ From b29f9c95d1dcade1aa3fd5fe8f264b5503368efe Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 16:01:07 +0200 Subject: [PATCH 27/36] PlayerController: Using CharacterEquipment for actual equipment --- src/logic/PlayerController.cpp | 188 +-------------------------------- 1 file changed, 2 insertions(+), 186 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 9d1678f6..9bfc4fd0 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -285,196 +285,12 @@ void PlayerController::onDebugDraw() void PlayerController::unequipItem(Daedalus::GameState::ItemHandle item) { - // Get item - Daedalus::GEngineClasses::C_Item& itemData = m_World.getScriptEngine().getGameState().getItem(item); - ModelVisual* model = getModelVisual(); - - EModelNode node = EModelNode::None; - - if ((itemData.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_EQUIPABLE) == 0) - return; // Can't equip - - // TODO: Don't forget if an item is already unequipped before executing stat changing script-code! - - // Put into set of all equipped items first, then differentiate between the item-types - m_EquipmentState.equippedItemsAll.erase(item); - - if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_2HD_AXE) != 0) - { - node = EModelNode::Longsword; - - // Take off 2h weapon - m_EquipmentState.equippedItems.equippedWeapon2h.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_2HD_SWD) != 0) - { - node = EModelNode::Longsword; - - // Take off 2h weapon - m_EquipmentState.equippedItems.equippedWeapon2h.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_CROSSBOW) != 0) - { - node = EModelNode::Crossbow; - - // Take off crossbow - m_EquipmentState.equippedItems.equippedCrossBow.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_BOW) != 0) - { - node = EModelNode::Bow; - - // Take off bow - m_EquipmentState.equippedItems.equippedBow.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_SWD) != 0) - { - node = EModelNode::Sword; - - // Take off 1h weapon - m_EquipmentState.equippedItems.equippedWeapon1h.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_AXE) != 0) - { - node = EModelNode::Sword; - - // Take off 1h weapon - m_EquipmentState.equippedItems.equippedWeapon1h.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_AMULET) != 0) - { - node = EModelNode::None; - - // Take off amulet - m_EquipmentState.equippedItems.equippedAmulet.invalidate(); - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_RING) != 0) - { - node = EModelNode::None; - - // Take off ring - m_EquipmentState.equippedItems.equippedRings.erase(item); - } - else if ((itemData.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_RUNE) != 0 || (itemData.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_MAGIC) != 0) - { - node = EModelNode::None; - - // Take off our rune/scroll - m_EquipmentState.equippedItems.equippedRunes.erase(item); - } - - // Show visual on the npc-model - if (node != EModelNode::None) - model->setNodeVisual("", node); + m_CharacterEquipment.unequipItem(item); } void PlayerController::equipItem(Daedalus::GameState::ItemHandle item) { - // Get item - Daedalus::GEngineClasses::C_Item& itemData = m_World.getScriptEngine().getGameState().getItem(item); - ModelVisual* model = getModelVisual(); - - if (!m_CharacterEquipment.isItemEquipable(item)) - return; // Can't equip - - EModelNode node = EModelNode::None; - - // TODO: Don't forget if an item is already equipped before executing stat changing script-code! - - // Put into set of all equipped items first, then differentiate between the item-types - m_EquipmentState.equippedItemsAll.insert(item); - - if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_2HD_AXE) != 0) - { - node = EModelNode::Longsword; - - // Take of any 1h weapon - m_EquipmentState.equippedItems.equippedWeapon1h.invalidate(); - model->setNodeVisual("", EModelNode::Sword); - - // Put on our 2h weapon - m_EquipmentState.equippedItems.equippedWeapon2h = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_2HD_SWD) != 0) - { - node = EModelNode::Longsword; - - // Take of any 1h weapon - m_EquipmentState.equippedItems.equippedWeapon1h.invalidate(); - model->setNodeVisual("", EModelNode::Sword); - - // Put on our 2h weapon - m_EquipmentState.equippedItems.equippedWeapon2h = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_CROSSBOW) != 0) - { - node = EModelNode::Crossbow; - - // Take off a bow - m_EquipmentState.equippedItems.equippedBow.invalidate(); - model->setNodeVisual("", EModelNode::Bow); - - // Put on our crossbow - m_EquipmentState.equippedItems.equippedCrossBow = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_BOW) != 0) - { - node = EModelNode::Bow; - - // Take off a crossbow - m_EquipmentState.equippedItems.equippedCrossBow.invalidate(); - model->setNodeVisual("", EModelNode::Crossbow); - - // Put on our bow - m_EquipmentState.equippedItems.equippedBow = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_SWD) != 0) - { - node = EModelNode::Sword; - - // Take of any 2h weapon - m_EquipmentState.equippedItems.equippedWeapon2h.invalidate(); - model->setNodeVisual("", EModelNode::Longsword); - - // Put on our 1h weapon - m_EquipmentState.equippedItems.equippedWeapon1h = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_AXE) != 0) - { - node = EModelNode::Sword; - - // Take of any 2h weapon - m_EquipmentState.equippedItems.equippedWeapon2h.invalidate(); - model->setNodeVisual("", EModelNode::Longsword); - - // Put on our 1h weapon - m_EquipmentState.equippedItems.equippedWeapon1h = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_AMULET) != 0) - { - node = EModelNode::None; - - // Put on our amulet - m_EquipmentState.equippedItems.equippedAmulet = item; - } - else if ((itemData.flags & Daedalus::GEngineClasses::C_Item::ITEM_RING) != 0) - { - node = EModelNode::None; - - // Put on our ring - m_EquipmentState.equippedItems.equippedRings.insert(item); - } - else if ((itemData.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_RUNE) != 0 || (itemData.mainflag & Daedalus::GEngineClasses::C_Item::ITM_CAT_MAGIC) != 0) - { - node = EModelNode::None; - - // Put on our rune/scroll - m_EquipmentState.equippedItems.equippedRunes.insert(item); - } - - // Show visual on the npc-model - if (node != EModelNode::None) - model->setNodeVisual(itemData.visual, node); + m_CharacterEquipment.equipItem(item); } Daedalus::GameState::ItemHandle PlayerController::drawWeaponMelee(bool forceFist) From 743fc2cdd2863e5241084442d438d4f5a9842925 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 16:20:32 +0200 Subject: [PATCH 28/36] CharacterEquipment: Add methods to put stuff into the players hands --- src/logic/CharacterEquipment.cpp | 39 ++++++++++++++++++++++++++------ src/logic/CharacterEquipment.h | 11 +++++++-- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index bea8290e..0bfc07e7 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -234,26 +234,34 @@ void Logic::CharacterEquipment::showBowWeaponOnCharacter() } } -void Logic::CharacterEquipment::showMeleeWeaponInCharactersHand() +void Logic::CharacterEquipment::putMeleeWeaponInCharactersHand() { using Daedalus::GEngineClasses::C_Item; auto item = getItemInSlot(Slot::MELEE); - setCharacterModelAttachment(getItemVisual(item), EModelNode::Righthand); + putItemIntoRightHand(item); + removeCharacterModelAttachment(EModelNode::Sword); + removeCharacterModelAttachment(EModelNode::Longsword); } -void Logic::CharacterEquipment::showBowWeaponOnCharactersHand() +void Logic::CharacterEquipment::putBowWeaponOnCharactersHand() { using Daedalus::GEngineClasses::C_Item; auto item = getItemInSlot(Slot::BOW); - setCharacterModelAttachment(getItemVisual(item), EModelNode::Righthand); + putItemIntoRightHand(item); + removeCharacterModelAttachment(EModelNode::Bow); + removeCharacterModelAttachment(EModelNode::Crossbow); } void Logic::CharacterEquipment::removeItemInCharactersHand() { removeCharacterModelAttachment(EModelNode::Lefthand); removeCharacterModelAttachment(EModelNode::Righthand); + + // Need to put those back onto the character if they exist + showBowWeaponOnCharacter(); + showMeleeWeaponOnCharacter(); } tl::optional CharacterEquipment::getCorrectSlotForItem(ItemHandle item) const @@ -469,9 +477,11 @@ bool Logic::CharacterEquipment::isItemEquipable(ItemHandle item) const bool CharacterEquipment::doAttributesAllowUse(ItemHandle item) const { - // Check attributes - Daedalus::GEngineClasses::C_Item& data = m_World.getScriptEngine().getGameState().getItem(item); - Daedalus::GEngineClasses::C_Npc& npc = getController().getScriptInstance(); + using Daedalus::GEngineClasses::C_Item; + using Daedalus::GEngineClasses::C_Npc; + + C_Item& data = m_World.getScriptEngine().getGameState().getItem(item); + C_Npc& npc = getController().getScriptInstance(); ScriptEngine& s = m_World.getScriptEngine(); for (size_t i = 0; i < Daedalus::GEngineClasses::C_Item::COND_ATR_MAX; i++) @@ -542,6 +552,11 @@ void CharacterEquipment::setCharacterModelAttachment(const std::string& visual, pVisual->setNodeVisual(visual, node); } +void Logic::CharacterEquipment::setCharacterModelAttachment(ItemHandle item, EModelNode node) +{ + setCharacterModelAttachment(getItemVisual(item), node); +} + void Logic::CharacterEquipment::removeCharacterModelAttachment(EModelNode node) { setCharacterModelAttachment("", node); @@ -571,3 +586,13 @@ void CharacterEquipment::switchCharacterModelArmor(const std::string& visual) pVisual->setBodyState(state); } + +void Logic::CharacterEquipment::putItemIntoRightHand(ItemHandle item) +{ + setCharacterModelAttachment(item, EModelNode::Righthand); +} + +void Logic::CharacterEquipment::putItemIntoLeftHand(ItemHandle item) +{ + setCharacterModelAttachment(item, EModelNode::Lefthand); +} diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index 42dad787..c78ead26 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -153,6 +153,12 @@ namespace Logic tl::optional getItemDataInSlot(Slot slot) const; ItemHandle getItemInSlot(Slot slot) const; + /** + * Shows the visual of the given item in the players hand + */ + void putItemIntoRightHand(ItemHandle item); + void putItemIntoLeftHand(ItemHandle item); + protected: /** @@ -190,14 +196,15 @@ namespace Logic * Removes the weapons from the characters body and shows them * inside their hand */ - void showMeleeWeaponInCharactersHand(); - void showBowWeaponOnCharactersHand(); + void putMeleeWeaponInCharactersHand(); + void putBowWeaponOnCharactersHand(); void removeItemInCharactersHand(); /** * Sets the visual attachment on the character model */ void setCharacterModelAttachment(const std::string& visual, EModelNode node); + void setCharacterModelAttachment(ItemHandle item, EModelNode node); void removeCharacterModelAttachment(EModelNode node); /** From 270de93c26438e1f5bea5b2a727f8f31dd6ccc73 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 16:45:57 +0200 Subject: [PATCH 29/36] PlayerController: Now utilizing the equipping functionality of the CharacterEquipment class --- src/logic/CharacterEquipment.cpp | 46 +++++++++++++++----- src/logic/CharacterEquipment.h | 31 +++++++++---- src/logic/PlayerController.cpp | 74 +++++++++++++------------------- 3 files changed, 88 insertions(+), 63 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 0bfc07e7..49d370c4 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -254,7 +254,7 @@ void Logic::CharacterEquipment::putBowWeaponOnCharactersHand() removeCharacterModelAttachment(EModelNode::Crossbow); } -void Logic::CharacterEquipment::removeItemInCharactersHand() +void Logic::CharacterEquipment::removeItemInCharactersHandAndShowWeaponsOnBodyAndShowWeaponsOnBody() { removeCharacterModelAttachment(EModelNode::Lefthand); removeCharacterModelAttachment(EModelNode::Righthand); @@ -291,25 +291,23 @@ tl::optional CharacterEquipment::getCorrectSlotForItem CharacterEquipment::Kind CharacterEquipment::getKindOfItem(ItemHandle item) const { using Daedalus::GEngineClasses::C_Item; - auto itemDataOpt = getDataOfItem(item); + auto itemData = getDataOfItem(item); - if (!itemDataOpt) + if (!itemData) return Kind::OTHER; - auto& itemData = *itemDataOpt; - // Only equippable items get a kind - if ((itemData.mainflag & C_Item::ITM_CAT_EQUIPABLE) == 0) + if ((itemData->mainflag & C_Item::ITM_CAT_EQUIPABLE) == 0) return Kind::OTHER; // Magic and armor can only be identified through the mainflags - if ((itemData.mainflag & C_Item::ITM_CAT_RUNE) != 0) + if ((itemData->mainflag & C_Item::ITM_CAT_RUNE) != 0) return Kind::MAGIC; - if ((itemData.mainflag & C_Item::ITM_CAT_MAGIC) != 0) + if ((itemData->mainflag & C_Item::ITM_CAT_MAGIC) != 0) return Kind::MAGIC; - if ((itemData.mainflag & C_Item::ITM_CAT_ARMOR) != 0) + if ((itemData->mainflag & C_Item::ITM_CAT_ARMOR) != 0) return Kind::ARMOR; std::pair pairs[] = { @@ -328,13 +326,41 @@ CharacterEquipment::Kind CharacterEquipment::getKindOfItem(ItemHandle item) cons for (auto& p : pairs) { - if (itemData.flags & p.first) + if (itemData->flags & p.first) return p.second; } return Kind::OTHER; } +CharacterEquipment::WeaponKind CharacterEquipment::getWeaponKindOfItem(ItemHandle item) const +{ + using Daedalus::GEngineClasses::C_Item; + + auto itemData = getDataOfItem(item); + + if (!itemData) + return WeaponKind::NONE; + + std::pair pairs[] = { + {C_Item::Flags::ITEM_DAG, WeaponKind::MELEE_1H}, + {C_Item::Flags::ITEM_SWD, WeaponKind::MELEE_1H}, + {C_Item::Flags::ITEM_AXE, WeaponKind::MELEE_1H}, + {C_Item::Flags::ITEM_2HD_SWD, WeaponKind::MELEE_2H}, + {C_Item::Flags::ITEM_2HD_AXE, WeaponKind::MELEE_2H}, + {C_Item::Flags::ITEM_BOW, WeaponKind::BOW}, + {C_Item::Flags::ITEM_CROSSBOW, WeaponKind::CROSSBOW}, + }; + + for (auto& p : pairs) + { + if (itemData->flags & p.first) + return p.second; + } + + return WeaponKind::NONE; +} + tl::optional CharacterEquipment::findAnyFreeMagicSlot() const { Slot possibleSlots[] = { diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index c78ead26..5154d087 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -63,6 +63,15 @@ namespace Logic OTHER, }; + enum class WeaponKind + { + MELEE_1H, + MELEE_2H, + BOW, + CROSSBOW, + NONE, + }; + CharacterEquipment(World::WorldInstance& world, Handle::EntityHandle characterEntity); /** @@ -104,6 +113,12 @@ namespace Logic */ Kind getKindOfItem(ItemHandle item) const; + /** + * @return More specific weapon type of the given item, ie. whether a weapon is 1 or 2 handed. + * If 'item' is not a weapon, it returns 'NONE'. + */ + WeaponKind getWeaponKindOfItem(ItemHandle item) const; + /** * Some types of items can be equipped to multiple slots. These functions * return the first free one they can find. @@ -159,6 +174,14 @@ namespace Logic void putItemIntoRightHand(ItemHandle item); void putItemIntoLeftHand(ItemHandle item); + /** + * Removes the weapons from the characters body and shows them + * inside their hand + */ + void putMeleeWeaponInCharactersHand(); + void putBowWeaponInCharactersHand(); + void removeItemInCharactersHandAndShowWeaponsOnBody(); + protected: /** @@ -192,14 +215,6 @@ namespace Logic void showMeleeWeaponOnCharacter(); void showBowWeaponOnCharacter(); - /** - * Removes the weapons from the characters body and shows them - * inside their hand - */ - void putMeleeWeaponInCharactersHand(); - void putBowWeaponOnCharactersHand(); - void removeItemInCharactersHand(); - /** * Sets the visual attachment on the character model */ diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 9bfc4fd0..e4390972 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -295,75 +295,59 @@ void PlayerController::equipItem(Daedalus::GameState::ItemHandle item) Daedalus::GameState::ItemHandle PlayerController::drawWeaponMelee(bool forceFist) { + using Daedalus::GameState::ItemHandle; + using Slot = CharacterEquipment::Slot; + using WeaponKind = CharacterEquipment::WeaponKind; + // Check if we already have a weapon in our hands if (m_EquipmentState.weaponMode != EWeaponMode::WeaponNone) return m_EquipmentState.activeWeapon; - ModelVisual* model = getModelVisual(); - // Remove anything that was active before putting something new there m_EquipmentState.activeWeapon.invalidate(); - // Check what kind of weapon we got here - if (!forceFist && m_EquipmentState.equippedItems.equippedWeapon1h.isValid()) - { - m_EquipmentState.activeWeapon = m_EquipmentState.equippedItems.equippedWeapon1h; - m_EquipmentState.weaponMode = EWeaponMode::Weapon1h; - } - else if (!forceFist && m_EquipmentState.equippedItems.equippedWeapon2h.isValid()) + if (forceFist) { - m_EquipmentState.activeWeapon = m_EquipmentState.equippedItems.equippedWeapon2h; - m_EquipmentState.weaponMode = EWeaponMode::Weapon2h; + m_EquipmentState.weaponMode = EWeaponMode::WeaponFist; } else { - m_EquipmentState.weaponMode = EWeaponMode::WeaponFist; - } + ItemHandle equippedWeapon = m_CharacterEquipment.getItemInSlot(Slot::MELEE); + m_EquipmentState.activeWeapon = equippedWeapon; - // Move the visual - if (m_EquipmentState.activeWeapon.isValid()) - { - // Get actual data of the weapon we are going to draw - Daedalus::GEngineClasses::C_Item& itemData = m_World.getScriptEngine().getGameState().getItem( - m_EquipmentState.activeWeapon); - - // Clear the possible on-body-visuals first - model->setNodeVisual("", EModelNode::Lefthand); - model->setNodeVisual("", EModelNode::Righthand); - model->setNodeVisual("", EModelNode::Sword); - model->setNodeVisual("", EModelNode::Longsword); - - // Put visual into hand - // TODO: Listen to ani-events for this! - model->setNodeVisual(itemData.visual, EModelNode::Righthand); + switch (m_CharacterEquipment.getWeaponKindOfItem(equippedWeapon)) + { + case WeaponKind::MELEE_1H: + m_EquipmentState.weaponMode = EWeaponMode::Weapon1h; + break; + + case WeaponKind::MELEE_2H: + m_EquipmentState.weaponMode = EWeaponMode::Weapon2h; + break; + + default: + // Not a melee weapon? + m_EquipmentState.weaponMode = EWeaponMode::WeaponNone; + break; + } } - // Couldn't draw anything + if(m_EquipmentState.activeWeapon.isValid()) + m_CharacterEquipment.putMeleeWeaponInCharactersHand(); + return m_EquipmentState.activeWeapon; } void PlayerController::undrawWeapon(bool force) { - ModelVisual* model = getModelVisual(); - // TODO: Listen to ani-events for this! // TODO: Even do an animation for this! // TODO: Implement force-flag - // Clear hands - model->setNodeVisual("", EModelNode::Lefthand); - model->setNodeVisual("", EModelNode::Righthand); - m_EquipmentState.weaponMode = EWeaponMode::WeaponNone; - - // activeWeapon should be only invalid when using fists - if (m_EquipmentState.activeWeapon.isValid()) - { - // reequip the currently active item - equipItem(m_EquipmentState.activeWeapon); + m_CharacterEquipment.removeItemInCharactersHandAndShowWeaponsOnBody(); - // Remove active weapon - m_EquipmentState.activeWeapon.invalidate(); - } + m_EquipmentState.weaponMode = EWeaponMode::WeaponNone; + m_EquipmentState.activeWeapon.invalidate(); } ModelVisual* PlayerController::getModelVisual() From 4ef369ca83108945edfc103f3705703aab5aac2a Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 16:51:01 +0200 Subject: [PATCH 30/36] CharacterEquipment: Fixed refactoring mistake --- src/logic/CharacterEquipment.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 49d370c4..9c4c4e9b 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -244,7 +244,7 @@ void Logic::CharacterEquipment::putMeleeWeaponInCharactersHand() removeCharacterModelAttachment(EModelNode::Longsword); } -void Logic::CharacterEquipment::putBowWeaponOnCharactersHand() +void Logic::CharacterEquipment::putBowWeaponInCharactersHand() { using Daedalus::GEngineClasses::C_Item; auto item = getItemInSlot(Slot::BOW); @@ -254,7 +254,7 @@ void Logic::CharacterEquipment::putBowWeaponOnCharactersHand() removeCharacterModelAttachment(EModelNode::Crossbow); } -void Logic::CharacterEquipment::removeItemInCharactersHandAndShowWeaponsOnBodyAndShowWeaponsOnBody() +void Logic::CharacterEquipment::removeItemInCharactersHandAndShowWeaponsOnBody() { removeCharacterModelAttachment(EModelNode::Lefthand); removeCharacterModelAttachment(EModelNode::Righthand); From 067146a9133e30bffa3bcaa4d798a176f7dd5b40 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 16:58:54 +0200 Subject: [PATCH 31/36] PlayerController: Fixed "hasEquippedMeleeWeapn" --- src/logic/PlayerController.cpp | 7 ++++++- src/logic/PlayerController.h | 5 +---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index e4390972..8404699c 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -293,6 +293,11 @@ void PlayerController::equipItem(Daedalus::GameState::ItemHandle item) m_CharacterEquipment.equipItem(item); } +bool Logic::PlayerController::hasEquippedMeleeWeapon() const +{ + return m_CharacterEquipment.hasMeleeWeaponEquipped(); +} + Daedalus::GameState::ItemHandle PlayerController::drawWeaponMelee(bool forceFist) { using Daedalus::GameState::ItemHandle; @@ -332,7 +337,7 @@ Daedalus::GameState::ItemHandle PlayerController::drawWeaponMelee(bool forceFist } } - if(m_EquipmentState.activeWeapon.isValid()) + if (m_EquipmentState.activeWeapon.isValid()) m_CharacterEquipment.putMeleeWeaponInCharactersHand(); return m_EquipmentState.activeWeapon; diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index e503b601..b2231ae5 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -422,10 +422,7 @@ namespace Logic /** * Check if this NPC has equipped any melee weapon */ - bool hasEquippedMeleeWeapon() const - { - return m_EquipmentState.equippedItems.equippedWeapon1h.isValid() || m_EquipmentState.equippedItems.equippedWeapon2h.isValid(); - }; + bool hasEquippedMeleeWeapon() const; /** * @param walkMode Whether we should be runnning, sneaking, etc From 09dfcd1af883bf37e668131f9ac27d955e2ff19a Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 18:02:14 +0200 Subject: [PATCH 32/36] ScriptEngine: Added method to get the instancename of a symbol --- src/logic/ScriptEngine.cpp | 5 +++++ src/logic/ScriptEngine.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/logic/ScriptEngine.cpp b/src/logic/ScriptEngine.cpp index 33881657..65492125 100644 --- a/src/logic/ScriptEngine.cpp +++ b/src/logic/ScriptEngine.cpp @@ -207,6 +207,11 @@ size_t ScriptEngine::getSymbolIndexByName(const std::string& name) return m_pVM->getDATFile().getSymbolIndexByName(name); } +std::string Logic::ScriptEngine::getSymbolNameByIndex(size_t idx) const +{ + return m_pVM->getDATFile().getSymbolByIndex(idx).name; +} + void ScriptEngine::onInventoryItemInserted(Daedalus::GameState::ItemHandle item, Daedalus::GameState::NpcHandle npc) { Daedalus::GEngineClasses::C_Item& itemData = getGameState().getItem(item); diff --git a/src/logic/ScriptEngine.h b/src/logic/ScriptEngine.h index 10434721..291ef083 100644 --- a/src/logic/ScriptEngine.h +++ b/src/logic/ScriptEngine.h @@ -107,6 +107,7 @@ namespace Logic * @return Symbol-index, -1 of not found */ size_t getSymbolIndexByName(const std::string& name); + std::string getSymbolNameByIndex(size_t idx) const; /** * Checks whether the given symbol exists From 8e6476d2a25ef408d8b940a0b4efa19d4c6207de Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 18:02:31 +0200 Subject: [PATCH 33/36] PlayerController: Saving equipment works again --- src/logic/CharacterEquipment.cpp | 70 ++++++++++++++++++++++++++++++-- src/logic/CharacterEquipment.h | 12 ++++++ src/logic/PlayerController.cpp | 32 +++++---------- src/logic/PlayerController.h | 15 ------- 4 files changed, 89 insertions(+), 40 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 9c4c4e9b..87152520 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -23,6 +23,8 @@ bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) if (!isItemTypeCorrectForSlot(item, slot)) return false; + LogInfo() << "Equipping item: " << getInstanceNameOfItem(item); + switch (getKindOfItem(item)) { case Kind::MELEE: @@ -206,6 +208,7 @@ void Logic::CharacterEquipment::showMeleeWeaponOnCharacter() else { // What is this? + return; } setCharacterModelAttachment(getItemVisual(item), node); @@ -372,7 +375,9 @@ tl::optional CharacterEquipment::findAnyFreeMagicSlot( Slot::MAGIC_5, Slot::MAGIC_6, Slot::MAGIC_7, - Slot::MAGIC_8}; + Slot::MAGIC_8, + Slot::MAGIC_9, + }; for (Slot s : possibleSlots) { @@ -468,7 +473,8 @@ bool CharacterEquipment::isItemTypeCorrectForSlot(ItemHandle item, Slot slot) co Slot::MAGIC_5, Slot::MAGIC_6, Slot::MAGIC_7, - Slot::MAGIC_8}; + Slot::MAGIC_8, + Slot::MAGIC_9}; for (Slot s : possibleSlots) { @@ -613,12 +619,68 @@ void CharacterEquipment::switchCharacterModelArmor(const std::string& visual) pVisual->setBodyState(state); } -void Logic::CharacterEquipment::putItemIntoRightHand(ItemHandle item) +void CharacterEquipment::putItemIntoRightHand(ItemHandle item) { setCharacterModelAttachment(item, EModelNode::Righthand); } -void Logic::CharacterEquipment::putItemIntoLeftHand(ItemHandle item) +void CharacterEquipment::putItemIntoLeftHand(ItemHandle item) { setCharacterModelAttachment(item, EModelNode::Lefthand); } + +void CharacterEquipment::exportSlots(json& j) const +{ + j["MELEE"] = getInstanceNameOfItem(getItemInSlot(Slot::MELEE)); + j["BOW"] = getInstanceNameOfItem(getItemInSlot(Slot::BOW)); + j["MAGIC_0"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_0)); + j["MAGIC_1"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_1)); + j["MAGIC_2"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_2)); + j["MAGIC_3"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_3)); + j["MAGIC_4"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_4)); + j["MAGIC_5"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_5)); + j["MAGIC_6"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_6)); + j["MAGIC_7"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_7)); + j["MAGIC_8"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_8)); + j["MAGIC_9"] = getInstanceNameOfItem(getItemInSlot(Slot::MAGIC_9)); + j["RING_LEFT"] = getInstanceNameOfItem(getItemInSlot(Slot::RING_LEFT)); + j["RING_RIGHT"] = getInstanceNameOfItem(getItemInSlot(Slot::RING_RIGHT)); + j["AMULET"] = getInstanceNameOfItem(getItemInSlot(Slot::AMULET)); + j["BELT"] = getInstanceNameOfItem(getItemInSlot(Slot::BELT)); + j["ARMOR"] = getInstanceNameOfItem(getItemInSlot(Slot::ARMOR)); +} + +void CharacterEquipment::importSlots(const json& j) +{ + auto& inventory = getController().getInventory(); + + equipItemToSlot(inventory.getItem(j["MELEE"].get()), Slot::MELEE); + equipItemToSlot(inventory.getItem(j["BOW"].get()), Slot::BOW); + equipItemToSlot(inventory.getItem(j["MAGIC_0"].get()), Slot::MAGIC_0); + equipItemToSlot(inventory.getItem(j["MAGIC_1"].get()), Slot::MAGIC_1); + equipItemToSlot(inventory.getItem(j["MAGIC_2"].get()), Slot::MAGIC_2); + equipItemToSlot(inventory.getItem(j["MAGIC_3"].get()), Slot::MAGIC_3); + equipItemToSlot(inventory.getItem(j["MAGIC_4"].get()), Slot::MAGIC_4); + equipItemToSlot(inventory.getItem(j["MAGIC_5"].get()), Slot::MAGIC_5); + equipItemToSlot(inventory.getItem(j["MAGIC_6"].get()), Slot::MAGIC_6); + equipItemToSlot(inventory.getItem(j["MAGIC_7"].get()), Slot::MAGIC_7); + equipItemToSlot(inventory.getItem(j["MAGIC_8"].get()), Slot::MAGIC_8); + equipItemToSlot(inventory.getItem(j["MAGIC_9"].get()), Slot::MAGIC_9); + equipItemToSlot(inventory.getItem(j["RING_LEFT"].get()), Slot::RING_LEFT); + equipItemToSlot(inventory.getItem(j["RING_RIGHT"].get()), Slot::RING_RIGHT); + equipItemToSlot(inventory.getItem(j["AMULET"].get()), Slot::AMULET); + equipItemToSlot(inventory.getItem(j["BELT"].get()), Slot::BELT); + equipItemToSlot(inventory.getItem(j["ARMOR"].get()), Slot::ARMOR); +} + +std::string Logic::CharacterEquipment::getInstanceNameOfItem(ItemHandle item) const +{ + auto data = getDataOfItem(item); + + if (!data) + return ""; + + ScriptEngine& s = m_World.getScriptEngine(); + + return s.getSymbolNameByIndex(data->instanceSymbol); +} diff --git a/src/logic/CharacterEquipment.h b/src/logic/CharacterEquipment.h index 5154d087..d9a60d07 100644 --- a/src/logic/CharacterEquipment.h +++ b/src/logic/CharacterEquipment.h @@ -182,6 +182,13 @@ namespace Logic void putBowWeaponInCharactersHand(); void removeItemInCharactersHandAndShowWeaponsOnBody(); + + /** + * Savegame serialization + */ + + void exportSlots(json& j) const; + void importSlots(const json& j); protected: /** @@ -248,6 +255,11 @@ namespace Logic */ std::string getItemVisual(ItemHandle item) const; + /** + * @return The script instance name of the given item + */ + std::string getInstanceNameOfItem(ItemHandle item) const; + World::WorldInstance& m_World; Handle::EntityHandle m_CharacterEntity; }; diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 8404699c..83c131e3 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -1481,16 +1481,17 @@ void PlayerController::exportPart(json& j) m_Inventory.exportInventory(j["inventory"]); // Export equipped items + m_CharacterEquipment.exportSlots(j["equipment"]); { - j["equipped"] = json::array(); - for (auto item : m_EquipmentState.equippedItemsAll) - { - // Write instance of the equipped item - Daedalus::GEngineClasses::C_Item& data = m_World.getScriptEngine().getGameState().getItem(item); - std::string instanceName = m_World.getScriptEngine().getVM().getDATFile().getSymbolByIndex(data.instanceSymbol).name; - - j["equipped"].push_back(instanceName); - } + // j["equipped"] = json::array(); + // for (auto item : m_EquipmentState.equippedItemsAll) + // { + // // Write instance of the equipped item + // Daedalus::GEngineClasses::C_Item& data = m_World.getScriptEngine().getGameState().getItem(item); + // std::string instanceName = m_World.getScriptEngine().getVM().getDATFile().getSymbolByIndex(data.instanceSymbol).name; + + // j["equipped"].push_back(instanceName); + // } } // export refusetalktime @@ -1562,18 +1563,7 @@ void PlayerController::importObject(const json& j, bool noTransform) m_Inventory.importInventory(j["inventory"]); // Import equipments - { - Inventory& inv = m_Inventory; - - for (const std::string& sym : j["equipped"]) - { - Daedalus::GameState::ItemHandle h = inv.getItem(sym); - - assert(h.isValid()); // Item to equip MUST be inside the inventory - - equipItem(h); - } - } + m_CharacterEquipment.importSlots(j["equipment"]); // import refusetalktime this->setRefuseTalkTime(static_cast(j["refusetalktime"])); diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index b2231ae5..22e8bb5d 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -520,21 +520,6 @@ namespace Logic EWeaponMode weaponMode; Daedalus::GameState::ItemHandle activeWeapon; - // All equiped items. Contains weapons, rings, armor... - std::set equippedItemsAll; - - // All possible equipped items on an NPC - struct - { - std::set equippedRings; - std::set equippedRunes; - Daedalus::GameState::ItemHandle equippedWeapon1h; - Daedalus::GameState::ItemHandle equippedWeapon2h; - Daedalus::GameState::ItemHandle equippedBow; - Daedalus::GameState::ItemHandle equippedCrossBow; - Daedalus::GameState::ItemHandle equippedBelt; - Daedalus::GameState::ItemHandle equippedAmulet; - } equippedItems; } m_EquipmentState; Inventory m_Inventory; From b0c2938d87c6917abd097b81d35939a90e755fbe Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 18:04:58 +0200 Subject: [PATCH 34/36] Savegames: Player-Info is now written as pretty json --- src/logic/SavegameManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logic/SavegameManager.cpp b/src/logic/SavegameManager.cpp index 3993f290..19240f70 100644 --- a/src/logic/SavegameManager.cpp +++ b/src/logic/SavegameManager.cpp @@ -147,7 +147,7 @@ Engine::SavegameManager::SavegameInfo SavegameManager::readSavegameInfo(int idx) bool SavegameManager::writePlayer(int idx, const std::string& playerName, const nlohmann::json& player) { - return writeFileInSlot(idx, playerName + ".json", Utils::iso_8859_1_to_utf8(player.dump())); + return writeFileInSlot(idx, playerName + ".json", Utils::iso_8859_1_to_utf8(player.dump(4))); } std::string SavegameManager::readPlayer(int idx, const std::string& playerName) From e4effc9b1073d36d6ad2e84bc7ccfe34763e2deb Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Sun, 1 Jul 2018 18:08:36 +0200 Subject: [PATCH 35/36] PlayerController: Removed outdated movement information --- src/logic/PlayerController.cpp | 5 ----- src/logic/PlayerController.h | 6 ------ 2 files changed, 11 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 83c131e3..2510a653 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -87,7 +87,6 @@ PlayerController::PlayerController(World::WorldInstance& world, , m_PathFinder(world) , m_CharacterEquipment(world, entity) { - m_AIState.closestWaypoint = 0; m_NPCProperties.enablePhysics = true; m_MoveState.direction = Math::float3(1, 0, 0); @@ -96,8 +95,6 @@ PlayerController::PlayerController(World::WorldInstance& world, m_MoveState.ground.triangleIndex = 0; m_MoveState.ground.waterDepth = 0; m_MoveState.ground.trianglePosition = Math::float3(0, 0, 0); - m_AIState.targetWaypoint = World::Waynet::INVALID_WAYPOINT; - m_AIState.closestWaypoint = World::Waynet::INVALID_WAYPOINT; m_ScriptState.npcHandle = scriptInstance; @@ -188,8 +185,6 @@ void PlayerController::onUpdate(float deltaTime) void PlayerController::teleportToWaypoint(size_t wp) { - m_AIState.closestWaypoint = wp; - teleportToPosition(m_World.getWaynet().waypoints[wp].position); setDirection(m_World.getWaynet().waypoints[wp].direction); diff --git a/src/logic/PlayerController.h b/src/logic/PlayerController.h index 22e8bb5d..a0166f4f 100644 --- a/src/logic/PlayerController.h +++ b/src/logic/PlayerController.h @@ -463,12 +463,6 @@ namespace Logic struct { - // Waypoint this NPC is closest to/was last positioned at - size_t closestWaypoint; - - // Waypoint the NPC is going to - size_t targetWaypoint; - // Handle to the Mob currently used by this NPC, if valid Handle::EntityHandle usedMob; From ddceec9f13507349eb5af40143a3a20f3420c342 Mon Sep 17 00:00:00 2001 From: Andre Taulien Date: Wed, 4 Jul 2018 22:05:34 +0200 Subject: [PATCH 36/36] CharacterEquipment: Remove unnessicary "using" directives --- src/logic/CharacterEquipment.cpp | 58 ++++++++++++++------------------ 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/src/logic/CharacterEquipment.cpp b/src/logic/CharacterEquipment.cpp index 87152520..c5b95385 100644 --- a/src/logic/CharacterEquipment.cpp +++ b/src/logic/CharacterEquipment.cpp @@ -56,7 +56,7 @@ bool CharacterEquipment::equipItemToSlot(ItemHandle item, Slot slot) return true; } -bool Logic::CharacterEquipment::equipItem(ItemHandle item) +bool CharacterEquipment::equipItem(ItemHandle item) { if (!isItemEquipable(item)) return false; @@ -91,7 +91,7 @@ bool Logic::CharacterEquipment::equipItem(ItemHandle item) return equipItemToSlot(item, *slot); } -void Logic::CharacterEquipment::unequipItemInSlot(Slot slot) +void CharacterEquipment::unequipItemInSlot(Slot slot) { switch (slot) { @@ -114,7 +114,7 @@ void Logic::CharacterEquipment::unequipItemInSlot(Slot slot) } } -void Logic::CharacterEquipment::unequipItem(ItemHandle item) +void CharacterEquipment::unequipItem(ItemHandle item) { auto slot = findSlotItemWasEquippedTo(item); @@ -124,50 +124,46 @@ void Logic::CharacterEquipment::unequipItem(ItemHandle item) } } -bool Logic::CharacterEquipment::equipMelee(ItemHandle item) +bool CharacterEquipment::equipMelee(ItemHandle item) { setItemInSlot(item, Slot::MELEE); return true; } -bool Logic::CharacterEquipment::equipBow(ItemHandle item) +bool CharacterEquipment::equipBow(ItemHandle item) { - using Daedalus::GEngineClasses::C_Item; - setItemInSlot(item, Slot::BOW); return true; } -bool Logic::CharacterEquipment::equipAmulet(ItemHandle item) +bool CharacterEquipment::equipAmulet(ItemHandle item) { setItemInSlot(item, Slot::AMULET); return true; } -bool Logic::CharacterEquipment::equipRing(ItemHandle item, Slot slot) +bool CharacterEquipment::equipRing(ItemHandle item, Slot slot) { setItemInSlot(item, slot); return true; } -bool Logic::CharacterEquipment::equipMagic(ItemHandle item, Slot slot) +bool CharacterEquipment::equipMagic(ItemHandle item, Slot slot) { setItemInSlot(item, slot); return true; } -bool Logic::CharacterEquipment::equipBelt(ItemHandle item) +bool CharacterEquipment::equipBelt(ItemHandle item) { setItemInSlot(item, Slot::BELT); return true; } -bool Logic::CharacterEquipment::equipArmor(ItemHandle item) +bool CharacterEquipment::equipArmor(ItemHandle item) { - using Daedalus::GEngineClasses::C_Item; - auto data = getDataOfItem(item); if (!data) @@ -178,7 +174,7 @@ bool Logic::CharacterEquipment::equipArmor(ItemHandle item) return true; } -void Logic::CharacterEquipment::showMeleeWeaponOnCharacter() +void CharacterEquipment::showMeleeWeaponOnCharacter() { using Daedalus::GEngineClasses::C_Item; @@ -214,7 +210,7 @@ void Logic::CharacterEquipment::showMeleeWeaponOnCharacter() setCharacterModelAttachment(getItemVisual(item), node); } -void Logic::CharacterEquipment::showBowWeaponOnCharacter() +void CharacterEquipment::showBowWeaponOnCharacter() { using Daedalus::GEngineClasses::C_Item; auto item = getItemInSlot(Slot::BOW); @@ -237,9 +233,8 @@ void Logic::CharacterEquipment::showBowWeaponOnCharacter() } } -void Logic::CharacterEquipment::putMeleeWeaponInCharactersHand() +void CharacterEquipment::putMeleeWeaponInCharactersHand() { - using Daedalus::GEngineClasses::C_Item; auto item = getItemInSlot(Slot::MELEE); putItemIntoRightHand(item); @@ -247,9 +242,8 @@ void Logic::CharacterEquipment::putMeleeWeaponInCharactersHand() removeCharacterModelAttachment(EModelNode::Longsword); } -void Logic::CharacterEquipment::putBowWeaponInCharactersHand() +void CharacterEquipment::putBowWeaponInCharactersHand() { - using Daedalus::GEngineClasses::C_Item; auto item = getItemInSlot(Slot::BOW); putItemIntoRightHand(item); @@ -257,7 +251,7 @@ void Logic::CharacterEquipment::putBowWeaponInCharactersHand() removeCharacterModelAttachment(EModelNode::Crossbow); } -void Logic::CharacterEquipment::removeItemInCharactersHandAndShowWeaponsOnBody() +void CharacterEquipment::removeItemInCharactersHandAndShowWeaponsOnBody() { removeCharacterModelAttachment(EModelNode::Lefthand); removeCharacterModelAttachment(EModelNode::Righthand); @@ -425,7 +419,7 @@ bool CharacterEquipment::hasBowEquipped() const return getItemInSlot(Slot::BOW).isValid(); } -bool Logic::CharacterEquipment::hasItemEquipped(ItemHandle item) const +bool CharacterEquipment::hasItemEquipped(ItemHandle item) const { for (auto h : m_ItemsBySlot) { @@ -497,12 +491,12 @@ bool CharacterEquipment::isItemTypeCorrectForSlot(ItemHandle item, Slot slot) co } } -bool Logic::CharacterEquipment::isItemOfKind(ItemHandle item, Kind kind) const +bool CharacterEquipment::isItemOfKind(ItemHandle item, Kind kind) const { return getKindOfItem(item) == kind; } -bool Logic::CharacterEquipment::isItemEquipable(ItemHandle item) const +bool CharacterEquipment::isItemEquipable(ItemHandle item) const { return !isItemOfKind(item, Kind::OTHER); // All but OTHER can be equipped } @@ -539,7 +533,7 @@ tl::optional CharacterEquipment::getItemDataInSlo return getDataOfItem(getItemInSlot(slot)); } -std::string Logic::CharacterEquipment::getItemVisual(ItemHandle item) const +std::string CharacterEquipment::getItemVisual(ItemHandle item) const { auto data = getDataOfItem(item); @@ -554,7 +548,7 @@ CharacterEquipment::ItemHandle CharacterEquipment::getItemInSlot(Slot slot) cons return m_ItemsBySlot[(size_t)slot]; } -void Logic::CharacterEquipment::setItemInSlot(ItemHandle item, Slot slot) +void CharacterEquipment::setItemInSlot(ItemHandle item, Slot slot) { m_ItemsBySlot[(size_t)slot] = item; } @@ -563,10 +557,10 @@ PlayerController& CharacterEquipment::getController() const { auto logic = m_World.getEntity(m_CharacterEntity).m_pLogicController; assert(logic != nullptr); - return *reinterpret_cast(logic); + return *reinterpret_cast(logic); } -tl::optional Logic::CharacterEquipment::getDataOfItem(ItemHandle item) const +tl::optional CharacterEquipment::getDataOfItem(ItemHandle item) const { if (!item.isValid()) return tl::nullopt; @@ -584,17 +578,17 @@ void CharacterEquipment::setCharacterModelAttachment(const std::string& visual, pVisual->setNodeVisual(visual, node); } -void Logic::CharacterEquipment::setCharacterModelAttachment(ItemHandle item, EModelNode node) +void CharacterEquipment::setCharacterModelAttachment(ItemHandle item, EModelNode node) { setCharacterModelAttachment(getItemVisual(item), node); } -void Logic::CharacterEquipment::removeCharacterModelAttachment(EModelNode node) +void CharacterEquipment::removeCharacterModelAttachment(EModelNode node) { setCharacterModelAttachment("", node); } -void Logic::CharacterEquipment::switchToDefaultCharacterModel() +void CharacterEquipment::switchToDefaultCharacterModel() { ModelVisual* pVisual = getController().getModelVisual(); @@ -673,7 +667,7 @@ void CharacterEquipment::importSlots(const json& j) equipItemToSlot(inventory.getItem(j["ARMOR"].get()), Slot::ARMOR); } -std::string Logic::CharacterEquipment::getInstanceNameOfItem(ItemHandle item) const +std::string CharacterEquipment::getInstanceNameOfItem(ItemHandle item) const { auto data = getDataOfItem(item);