From f3185ec6bcc05fdf766e84f63dc16f0b047d5201 Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Mon, 7 May 2018 08:03:37 +0300 Subject: [PATCH] Shooting --- build/gamesource/config/entities/classes.ent | 37 +- build/gamesource/config/entities/defaults.ent | 4 +- proj/sxgame/vs2013/sxgame.vcxproj | 6 + proj/sxgame/vs2013/sxgame.vcxproj.filters | 18 + sdks/bullet3 | 2 +- source/anim/animated.cpp | 6 +- source/anim/animated.h | 2 +- source/anim/sxanim.h | 3 +- source/common | 2 +- source/decals/DecalManager.cpp | 19 +- source/decals/DecalManager.h | 6 +- source/game/BaseAmmo.cpp | 395 +++++++++++++++++- source/game/BaseAmmo.h | 41 +- source/game/BaseAnimating.h | 4 +- source/game/BaseCharacter.cpp | 146 ++++++- source/game/BaseCharacter.h | 26 ++ source/game/BaseEntity.cpp | 40 +- source/game/BaseEntity.h | 11 + source/game/BaseItem.cpp | 2 +- source/game/BaseMag.cpp | 4 + source/game/BaseSupply.h | 5 + source/game/BaseTool.cpp | 55 ++- source/game/BaseTool.h | 14 + source/game/BaseTrigger.cpp | 4 +- source/game/BaseWeapon.cpp | 251 +++++++++-- source/game/BaseWeapon.h | 34 +- source/game/CharacterInventory.cpp | 163 ++++++++ source/game/CharacterInventory.h | 32 ++ source/game/GameData.cpp | 7 + source/game/NPCBase.cpp | 30 +- source/game/NPCBase.h | 16 +- source/game/NPCZombie.cpp | 4 +- source/game/Player.cpp | 16 +- source/game/Random.h | 21 + source/game/TakeDamageInfo.h | 34 ++ source/game/Tracer.cpp | 129 ++++++ source/game/Tracer.h | 46 ++ source/mtllight/material.cpp | 5 + source/physics/PhyWorld.cpp | 56 ++- source/physics/PhyWorld.h | 7 +- source/physics/sxphysics.h | 33 ++ source/physics/sxphysics_dll.cpp | 15 +- source/skyxengine.cpp | 5 + 43 files changed, 1601 insertions(+), 155 deletions(-) create mode 100644 source/game/CharacterInventory.cpp create mode 100644 source/game/CharacterInventory.h create mode 100644 source/game/Random.h create mode 100644 source/game/TakeDamageInfo.h create mode 100644 source/game/Tracer.cpp create mode 100644 source/game/Tracer.h diff --git a/build/gamesource/config/entities/classes.ent b/build/gamesource/config/entities/classes.ent index 8b2422ed1..ef9771264 100644 --- a/build/gamesource/config/entities/classes.ent +++ b/build/gamesource/config/entities/classes.ent @@ -1,12 +1,19 @@ [ammo_5.45x39ps] base_class = base_ammo show_in_listing = 1 -model = "models/ammo/ammo_5.45x39.dse" +inv_stackable = 1 +inv_stack_max = 300 +; model = "models/ammo/ammo_5.45x39.dse" inv_name = "5.45x39ps" ;начальная скорость пули, ее масса, бронепробиваемость, останавливающее действие start_speed = 900 ; м/с bullet_mass = 3.4 ; г armor_piercing = 500 ; ед/дж +is_expansive = 0 ; экспансивная +is_bursting = 0 ; разрывная +; коэффициент формы +; наличие/отсутствие сердечника +; вращение об/с - зависит от шачальной скорости, шага нареза [ammobox_5.45x39ps] base_class = base_ammobox @@ -44,17 +51,23 @@ addon_handlers = "" zoom_time = 0.125 zoomable = 1 -fire_modes = "single,burst"; single/burst/cutoff -; cutoff_size = 3 -; cutoff_speed = 100 -single_speed = 40; выст/мин -burst_speed = 100; выст/мин +aiming_range = 200 ; м, дистанция пристрелки + +fire_modes = "single,burst,cutoff"; single/burst/cutoff +cutoff_size = 3 +single_rate = 400; выст/мин +burst_rate = 600; выст/мин +cutoff_rate = 600; выст/мин effective_distance = 650 ;разброс spread_base = 0.33 ;угол (в градусах) базовой дисперсии оружия (оружия, зажатого в тисках) +; тип нарезки ствола: 0 - гладкоствольное; -1 - левая; 1 - правая +rifle_type = 1 ; +rifle_step = 200 ; шаг нарезки, мм + ; Боевая скорострельность (одиночными): 40 выст/мин ; Боевая скорострельность (очередями): 100 выст/мин ; Дальность, до которой сохраняется убойное действие пули: 1350 м @@ -71,12 +84,12 @@ spread_base = 0.33 ;угол (в градусах) базовой ди ; звуки -snd_draw = ; Достать -snd_holster = ; Убрать -snd_shoot = "ak74_shoot2.ogg" ; Стрелять -snd_empty = ; Пустой -snd_reload = ; Перезарядка -snd_switch = ; Переключение режима +snd_draw = "wpn/ak74_draw.ogg" ; Достать +snd_holster = "wpn/generic_holster.ogg" ; Убрать +snd_shoot = "wpn/ak74_shoot2.ogg" ; Стрелять +snd_empty = "wpn/gen_empty.ogg" ; Пустой +snd_reload = "wpn/ak74_reload.ogg" ; Перезарядка +snd_switch = "wpn/generic_close.ogg" ; Переключение режима ;прочность durability_max = 350000 diff --git a/build/gamesource/config/entities/defaults.ent b/build/gamesource/config/entities/defaults.ent index b61b09092..70fb6cda8 100644 --- a/build/gamesource/config/entities/defaults.ent +++ b/build/gamesource/config/entities/defaults.ent @@ -1,3 +1,5 @@ [npc_zombie] -model = "models/zombie/zombie.dse" +; model = "models/zombie/zombie.dse" +; model = "models/zombie/zombie_hb.dse" +model = "models/stalker_zombi/stalker_zombi_a.dse" diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index 5d98a16f4..f4c7b56df 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -99,6 +99,7 @@ <ClCompile Include="..\..\..\source\game\BaseWeaponAddon.cpp" /> <ClCompile Include="..\..\..\source\game\BaseTrigger.cpp" /> <ClCompile Include="..\..\..\source\game\BaseCharacter.cpp" /> + <ClCompile Include="..\..\..\source\game\CharacterInventory.cpp" /> <ClCompile Include="..\..\..\source\game\crosshair.cpp" /> <ClCompile Include="..\..\..\source\game\CrosshairManager.cpp" /> <ClCompile Include="..\..\..\source\game\EntityFactory.cpp" /> @@ -126,6 +127,7 @@ <ClCompile Include="..\..\..\source\game\PlayerSpawn.cpp" /> <ClCompile Include="..\..\..\source\game\PointCamera.cpp" /> <ClCompile Include="..\..\..\source\game\PointEntity.cpp" /> + <ClCompile Include="..\..\..\source\game\Tracer.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\common\AAString.h" /> @@ -136,6 +138,8 @@ <ClInclude Include="..\..\..\source\game\BaseWeaponAddon.h" /> <ClInclude Include="..\..\..\source\game\BaseTrigger.h" /> <ClInclude Include="..\..\..\source\game\BaseCharacter.h" /> + <ClInclude Include="..\..\..\source\game\CharacterInventory.h" /> + <ClInclude Include="..\..\..\source\game\Random.h" /> <ClInclude Include="..\..\..\source\game\crosshair.h" /> <ClInclude Include="..\..\..\source\game\CrosshairManager.h" /> <ClInclude Include="..\..\..\source\game\EntityFactory.h" /> @@ -165,6 +169,8 @@ <ClInclude Include="..\..\..\source\game\PlayerSpawn.h" /> <ClInclude Include="..\..\..\source\game\PointCamera.h" /> <ClInclude Include="..\..\..\source\game\PointEntity.h" /> + <ClInclude Include="..\..\..\source\game\TakeDamageInfo.h" /> + <ClInclude Include="..\..\..\source\game\Tracer.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index 1fd6f5807..1a4129b7a 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -168,6 +168,12 @@ <ClCompile Include="..\..\..\source\game\BaseAmmoBox.cpp"> <Filter>Source Files\ents\items</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\game\Tracer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\game\CharacterInventory.cpp"> + <Filter>Source Files\ents</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -281,5 +287,17 @@ <ClInclude Include="..\..\..\source\game\BasePistol.h"> <Filter>Header Files\ents\items\tools\weapons</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\Random.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\Tracer.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\TakeDamageInfo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\CharacterInventory.h"> + <Filter>Header Files\ents</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/sdks/bullet3 b/sdks/bullet3 index 6c9124b10..c04199762 160000 --- a/sdks/bullet3 +++ b/sdks/bullet3 @@ -1 +1 @@ -Subproject commit 6c9124b1059924bac1f7bd347fabd3ab2ecd76e7 +Subproject commit c04199762e5e6e2161585ade2a22be2d355bf6ce diff --git a/source/anim/animated.cpp b/source/anim/animated.cpp index 47b08aa5b..505be3e7e 100644 --- a/source/anim/animated.cpp +++ b/source/anim/animated.cpp @@ -1075,7 +1075,7 @@ Animation::~Animation() m_pMgr->unreg(myId); } -SMMATRIX Animation::getBoneTransform(UINT _id) +SMMATRIX Animation::getBoneTransform(UINT _id, bool bWithScale) { //id *= 2; int id = m_FinalBones[_id].pid; @@ -1084,6 +1084,10 @@ SMMATRIX Animation::getBoneTransform(UINT _id) return(SMMatrixIdentity()); } float3 pos = m_pBoneMatrixRender[id].position/* * m_fScale*/; + if(bWithScale) + { + pos *= m_fScale; + } SMQuaternion q = m_pBoneMatrixRender[id].orient; return(q.GetMatrix() * SMMatrixTranslation(pos)); } diff --git a/source/anim/animated.h b/source/anim/animated.h index 22a50c8cf..41df6124b 100644 --- a/source/anim/animated.h +++ b/source/anim/animated.h @@ -150,7 +150,7 @@ public: void setBoneController(const String & name, float value, MODEL_BONE_CTL what); - SMMATRIX getBoneTransform(UINT id); + SMMATRIX getBoneTransform(UINT id, bool bWithScale = false); float3 getBoneTransformPos(UINT id); SMQuaternion getBoneTransformRot(UINT id); UINT getBone(const char * str); diff --git a/source/anim/sxanim.h b/source/anim/sxanim.h index ee094dae3..92aca21b1 100644 --- a/source/anim/sxanim.h +++ b/source/anim/sxanim.h @@ -166,9 +166,10 @@ public: /*! Возвращает трансформацию указанной кости @param[in] id Номер кости + @param[in] bWithScale Учитывать ли масштабирование @return Матрица трансформации кости */ - virtual SMMATRIX getBoneTransform(UINT id) = 0; + virtual SMMATRIX getBoneTransform(UINT id, bool bWithScale = false) = 0; /*! Возвращает идентификатор указанной кости @param[in] str Имя кости diff --git a/source/common b/source/common index 6d30eb4c6..1ad20f60b 160000 --- a/source/common +++ b/source/common @@ -1 +1 @@ -Subproject commit 6d30eb4c6e806568c952dffbd90d3ae59ff01a43 +Subproject commit 1ad20f60bbac0b2d9496c64d3ef35cea0fa51b88 diff --git a/source/decals/DecalManager.cpp b/source/decals/DecalManager.cpp index d5e3833bc..281fdd004 100644 --- a/source/decals/DecalManager.cpp +++ b/source/decals/DecalManager.cpp @@ -446,7 +446,7 @@ void DecalManager::shootDecal(DECAL_TYPE type, const float3 & position, ID iMate btTriangleMeshShape * shape = (btTriangleMeshShape*)part->m_hitCollisionObject->getCollisionShape(); btStridingMeshInterface * iface = shape->getMeshInterface(); - float3_t * verices; + float3 * verices; int numverts; PHY_ScalarType type = PHY_INTEGER; int stride = 0; @@ -526,6 +526,7 @@ void DecalManager::shootDecal(DECAL_TYPE type, const float3 & position, ID iMate vClippedVerts[ii + 1].z = nn; // fix normal //Transform to World vDecalVerts.push_back(vert0); + //m_dbgRender.push_back(vert0.pos); vert.pos = mBasis * vClippedVerts[ii]; vert.normal = n; @@ -533,11 +534,14 @@ void DecalManager::shootDecal(DECAL_TYPE type, const float3 & position, ID iMate vert.tex = (float2)(vert.tex * float2((float)(rng.xmax - rng.xmin) / (float)_info.Width, (float)(rng.ymax - rng.ymin) / (float)_info.Height) + float2((float)rng.xmin / (float)_info.Width, (float)rng.ymin / (float)_info.Height)); vDecalVerts.push_back(vert); + //m_dbgRender.push_back(vert.pos); vert.pos = mBasis * vClippedVerts[ii + 1]; vert.tex = float2((vClippedVerts[ii + 1].x - sBound.x) / (sBound.y - sBound.x), (vClippedVerts[ii + 1].y - tBound.x) / (tBound.y - tBound.x)); vert.tex = (float2)(vert.tex * float2((float)(rng.xmax - rng.xmin) / (float)_info.Width, (float)(rng.ymax - rng.ymin) / (float)_info.Height) + float2((float)rng.xmin / (float)_info.Width, (float)rng.ymin / (float)_info.Height)); vDecalVerts.push_back(vert); + //m_dbgRender.push_back(vert.pos); + //m_dbgRender.push_back(mBasis * vClippedVerts[ii]); //m_dbgRender.push_back(mBasis * vClippedVerts[(ii + 1) % len]); @@ -560,12 +564,12 @@ void DecalManager::shootDecal(DECAL_TYPE type, const float3 & position, ID iMate void DecalManager::render() { - /*for(int i = 0, l = g_dbgDraw.size(); i < l; i += 3) + /*for(int i = 0, l = m_dbgRender.size(); i < l; i += 3) { - SXPhysics_GetDynWorld()->getDebugDrawer()->drawTriangle(F3_BTVEC(g_dbgDraw[i]), F3_BTVEC(g_dbgDraw[i + 1]), F3_BTVEC(g_dbgDraw[i + 2]), btVector3(1.0f, 1.0f, 1.0f), 1.0f); - } - SXPhysics_GetDynWorld()->getDebugDrawer()->drawSphere(F3_BTVEC(spherePos), spherePos.w, btVector3(1, 1, 1)); - */ + SXPhysics_GetDynWorld()->getDebugDrawer()->drawTriangle(F3_BTVEC(m_dbgRender[i]), F3_BTVEC(m_dbgRender[i + 1]), F3_BTVEC(m_dbgRender[i + 2]), btVector3(1.0f, 1.0f, 1.0f), 1.0f); + }*/ + //SXPhysics_GetDynWorld()->getDebugDrawer()->drawSphere(F3_BTVEC(spherePos), spherePos.w, btVector3(1, 1, 1)); + updateBuffer(); if(!m_pVertexBuffer) @@ -573,10 +577,7 @@ void DecalManager::render() return; } - dev->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1); - - //SkyXEngine::Core::Data::Device->SetTexture(0, SkyXEngine::Core::Data::LoadedTextures->GetTexture(3)); dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); diff --git a/source/decals/DecalManager.h b/source/decals/DecalManager.h index f150cc1da..ccce0c0ea 100644 --- a/source/decals/DecalManager.h +++ b/source/decals/DecalManager.h @@ -181,7 +181,7 @@ public: } // floor/ceiling? - if(fabs(surfaceNormal.z) > SIN_45_DEGREES) + if(fabs(surfaceNormal.y) > SIN_45_DEGREES) { textureSpaceBasis[0].x = 1.0f; textureSpaceBasis[0].y = 0.0f; @@ -197,8 +197,8 @@ public: else { textureSpaceBasis[1].x = 0.0f; - textureSpaceBasis[1].y = 0.0f; - textureSpaceBasis[1].z = -1.0f; + textureSpaceBasis[1].y = -1.0f; + textureSpaceBasis[1].z = 0.0f; // S = N cross T textureSpaceBasis[0] = SMVector3Cross(textureSpaceBasis[2], textureSpaceBasis[1]); diff --git a/source/game/BaseAmmo.cpp b/source/game/BaseAmmo.cpp index aaa93334c..41440c58a 100644 --- a/source/game/BaseAmmo.cpp +++ b/source/game/BaseAmmo.cpp @@ -5,6 +5,11 @@ See the license in LICENSE ***********************************************************/ #include "BaseAmmo.h" +#include "Tracer.h" +#include "BaseTool.h" +#include <particles/sxparticles.h> +#include <decals/sxdecals.h> +#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h> /*! \skydocent base_ammo Базовый класс для патронов @@ -17,16 +22,404 @@ BEGIN_PROPTABLE(CBaseAmmo) DEFINE_FIELD_FLOAT(m_fBulletMass, PDFF_NOEDIT | PDFF_NOEXPORT, "bullet_mass", "", EDITOR_NONE) //! Бронебойность DEFINE_FIELD_FLOAT(m_fArmorPiercing, PDFF_NOEDIT | PDFF_NOEXPORT, "armor_piercing", "", EDITOR_NONE) + //! Экспансивная? + DEFINE_FIELD_BOOL(m_isExpansive, PDFF_NOEDIT | PDFF_NOEXPORT, "is_expansive", "", EDITOR_NONE) + //! Разрывная? + DEFINE_FIELD_BOOL(m_isBursting, PDFF_NOEDIT | PDFF_NOEXPORT, "is_bursting", "", EDITOR_NONE) END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseAmmo, base_ammo); +struct AllHitsNotMeRayResultCallback: public btCollisionWorld::AllHitsRayResultCallback +{ + AllHitsNotMeRayResultCallback(btCollisionObject* me, const btVector3& rayFromWorld, const btVector3& rayToWorld): + AllHitsRayResultCallback(rayFromWorld, rayToWorld) + { + m_me = me; + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) + { + //printf("%f\n", rayResult.m_hitFraction); + if(rayResult.m_collisionObject == m_me) + { + return 1.0; + } + if(rayResult.m_localShapeInfo) + { + m_shapeInfos.push_back(*rayResult.m_localShapeInfo); + } + else + { + m_shapeInfos.push_back({-1, -1}); + } + return(AllHitsRayResultCallback::addSingleResult(rayResult, normalInWorldSpace)); + } + Array<btCollisionWorld::LocalShapeInfo> m_shapeInfos; +protected: + btCollisionObject* m_me; +}; + CBaseAmmo::CBaseAmmo(CEntityManager * pMgr): BaseClass(pMgr), m_fStartSpeed(0.0f), m_fBulletMass(0.0f), - m_fArmorPiercing(0.0f) + m_fArmorPiercing(0.0f), + m_fNextBarrierDepth(0.0f) { m_bPickable = false; m_bInvStackable = false; } + +void CBaseAmmo::fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker) +{ + extern CTracer *g_pTracer; + + fire(vStart, vDir, pAttacker, m_fStartSpeed); +} + +void CBaseAmmo::fire(const float3 &_vStart, const float3 &_vDir, CBaseCharacter *pAttacker, float fSpeed) +{ + extern CTracer *g_pTracer; + + int iJump = 0; + + float3 vStart = _vStart; + float3 vDir = _vDir; + float fMaxDistance = ((CBaseTool*)getParent())->getMaxDistance(); + + float3 end; + float t0 = 0.0f; + float fY0; + bool isY0set = false; + float fSpeedY0; + g_pTracer->begin(vStart); + + while(iJump < BULLET_MAX_JUMPS && fSpeed > 0.5f && fMaxDistance > 0.0f) + { + end = vStart + SMVector3Normalize(vDir) * min(fMaxDistance, BULLET_STEP_DISTANCE); + if(!isY0set) + { + fY0 = end.y; + isY0set = true; + fSpeedY0 = fSpeed * (vDir.y / SMVector3Length(vDir)); + } + AllHitsNotMeRayResultCallback cb(pAttacker ? pAttacker->getBtCollisionObject() : NULL, F3_BTVEC(vStart), F3_BTVEC(end)); + cb.m_collisionFilterGroup = CG_BULLETFIRE; + cb.m_collisionFilterMask = CG_ALL & ~(CG_DEBRIS | CG_TRIGGER | CG_CHARACTER); + cb.m_flags |= btTriangleRaycastCallback::kF_FilterBackfaces; + SXPhysics_GetDynWorld()->rayTest(F3_BTVEC(vStart), F3_BTVEC(end), cb); + + g_pTracer->lineTo(vStart, 0.0f); + //g_pTracer->begin(vStart); + if(cb.hasHit()) + { + AllHitsNotMeRayResultCallback cbBack(pAttacker ? pAttacker->getBtCollisionObject() : NULL, F3_BTVEC(end), F3_BTVEC(vStart)); + cbBack.m_flags |= btTriangleRaycastCallback::kF_FilterBackfaces; + SXPhysics_GetDynWorld()->rayTest(F3_BTVEC(end), F3_BTVEC(vStart), cbBack); + + Array<HitPoint> aHitPoints; + aHitPoints.reserve(cb.m_hitFractions.size() + cbBack.m_hitFractions.size()); + + for(int i = 0, l = cb.m_hitFractions.size(); i < l; ++i) + { + aHitPoints.push_back({BTVEC_F3(cb.m_hitPointWorld[i]), BTVEC_F3(cb.m_hitNormalWorld[i]), cb.m_collisionObjects[i], cb.m_hitFractions[i], false, cb.m_shapeInfos[i]}); + } + for(int i = 0, l = cbBack.m_hitFractions.size(); i < l; ++i) + { + aHitPoints.push_back({BTVEC_F3(cbBack.m_hitPointWorld[i]), BTVEC_F3(cbBack.m_hitNormalWorld[i]), cbBack.m_collisionObjects[i], 1.0f - cbBack.m_hitFractions[i], true, cbBack.m_shapeInfos[i]}); + } + + aHitPoints.quickSort([](const HitPoint &a, const HitPoint &b) + { + return(a.fFraction < b.fFraction); + }); + for(int i = 0, l = aHitPoints.size(); i < l; ++i) + { + + ID idMtl = SXPhysics_GetMtlID(aHitPoints[i].pCollisionObject, &aHitPoints[i].shapeInfo); + if(ID_VALID(idMtl) && !aHitPoints[i].isExit) + { + float fHitChance = SML_MtlGetHitChance(idMtl); + if(fHitChance < randf(0.0f, 1.0f)) + { + int c = 0; + for(int j = i + 1; j < l; ++j) + { + if(aHitPoints[j].isExit) + { + if(c == 0) + { + aHitPoints.erase(j); + --l; + break; + } + --c; + } + else + { + ++c; + } + } + aHitPoints.erase(i--); + --l; + //skip that + continue; + } + } + g_pTracer->lineTo(aHitPoints[i].vPosition, aHitPoints[i].isExit ? 0.0f : 1.0f); + shootDecal(aHitPoints[i].vPosition, aHitPoints[i].vNormal, idMtl); + if(!aHitPoints[i].isExit) + { + m_fNextBarrierDepth = 0.0f; + // find next exit + // calculate can we hole + for(int j = i + 1; j < l; ++j) + { + if(aHitPoints[j].isExit) + { + m_fNextBarrierDepth = SMVector3Length(aHitPoints[j].vPosition - aHitPoints[i].vPosition); + break; + } + } + float3 vNewDir; + float fNewSpeed = fSpeed; + if(shouldRecochet(aHitPoints[i].vPosition, aHitPoints[i].vNormal, vDir, idMtl, fSpeed, &vNewDir, &fNewSpeed)) + { + // @TODO: play recochet sound + } + + float fEnergyDelta = m_fBulletMass * 0.001f * 0.5f * (fSpeed * fSpeed - fNewSpeed * fNewSpeed); + + if(aHitPoints[i].pCollisionObject->getUserPointer()) + { + CTakeDamageInfo takeDamageInfo(pAttacker, fEnergyDelta); + takeDamageInfo.m_pInflictor = getParent(); + + ((CBaseEntity*)aHitPoints[i].pCollisionObject->getUserPointer())->dispatchDamage(takeDamageInfo); + } + + + // restart fire with new dir and speed + + float3 vStart2 = aHitPoints[i].vPosition + SMVector3Normalize(vDir) * 0.001f; + vDir = vNewDir; + fSpeed = fNewSpeed; + + fMaxDistance -= SMVector3Length(vStart - vStart2); + vStart = vStart2; + + t0 = 0.0f; + isY0set = false; + ++iJump; + //fire(aHitPoints[i].vPosition + SMVector3Normalize(vDir) * 0.001f, vNewDir, pAttacker, fNewSpeed, iJump + 1); + break; + } + + } + + + + //shoot decal + //SXDecals_ShootDecal(DECAL_TYPE_CONCRETE, BTVEC_F3(cb.m_hitPointWorld[0]), BTVEC_F3(cb.m_hitNormalWorld[0])); + //SPE_EffectPlayByName("fire", &BTVEC_F3(cb.m_hitPointWorld), &BTVEC_F3(cb.m_hitNormalWorld)); + /*if(!cb.m_collisionObject->isStaticOrKinematicObject()) + { + ((btRigidBody*)cb.m_collisionObject)->applyCentralImpulse(F3_BTVEC(vDir * 10.0f)); + cb.m_collisionObject->activate(); + }*/ + //g_pTracer->lineTo(BTVEC_F3(cb.m_hitPointWorld[0]) + SMVector3Normalize(BTVEC_F3(cb.m_hitNormalWorld[0])) * 0.1f, 0.0f); + } + else + { + g_pTracer->lineTo(end, 1.0f); + fMaxDistance -= min(fMaxDistance, BULLET_STEP_DISTANCE); + float t1 = t0 + (min(fMaxDistance, BULLET_STEP_DISTANCE) / fSpeed); + float3 vNewStart = end; + // apply derivation + // and... + // apply wind + // end... + + // apply gravity + //end.y += (fSpeed * (vDir.y / SMVector3Length(vDir)) * (t1 - t0) - 10.0f * 0.5f * (t1 * t1 - t0 * t0)); // 10.0f - gravity + end.y = fY0 + fSpeedY0 * t0 - 10.0f * 0.5f * t0 * t0; + + vDir = SMVector3Normalize(end - vStart); + + vStart = vNewStart; + t0 = t1; + } + } + g_pTracer->end(); +} + +void CBaseAmmo::shootDecal(const float3 &vPos, const float3 &vNormal, ID idMtl) +{ + if(ID_VALID(idMtl)) + { + MTLTYPE_PHYSIC type = SML_MtlGetPhysicMaterial(idMtl); + DECAL_TYPE decalType = DECAL_TYPE_CONCRETE; + switch(type) + { + case MTLTYPE_PHYSIC_METAL: + decalType = DECAL_TYPE_METAL; + break; + case MTLTYPE_PHYSIC_FLESH: + decalType = DECAL_TYPE_FLESH; + break; + case MTLTYPE_PHYSIC_GROUD_SAND: + decalType = DECAL_TYPE_EARTH; + break; + case MTLTYPE_PHYSIC_PLASTIC: + decalType = DECAL_TYPE_PLASTIC; + break; + case MTLTYPE_PHYSIC_TREE: + decalType = DECAL_TYPE_WOOD; + break; + } + SXDecals_ShootDecal(decalType, vPos, vNormal); + + //SPE_EffectPlayByName("create_decal_test", &aHitPoints[i].vPosition, &aHitPoints[i].vNormal); + } +} + +bool CBaseAmmo::shouldRecochet(const float3 &vPos, const float3 &vNormal, const float3 &vDir, ID idMtl, float fSpeed, float3 *pvNewDir, float *pfNewSpeed) +{ + //m_fArmorPiercing ^ => chance ^ + //fDurability ^ => chance ^ + //angle(-dir, normal) > 87 && m_isBursting => chance = 0 + //if(angle(-dir, normal) -> 90) + //{ + // fDensity ^ => xAngle ^ + //} + //else if(angle(-dir, normal) -> 0) + //{ + // fDensity ^ => chance ^ + // if(canHole()) + // { + // chance = 0 + // } + // else + // { + // chance ^ + // } + //} + //m_isExpansive => chance = 0 + // + float fDurability = 10; + float fDensity = 1000; + bool isNewSpeedSet = false; + if(ID_VALID(idMtl)) + { + fDurability = SML_MtlGetPenetration(idMtl); // прочность + fDensity = SML_MtlGetDensity(idMtl); // плотность + if(fDurability <= 0) + { + fDurability = 10; + } + } + float fChance = 0.05f; + float fXangle = 0.0f; + float fAngleDirNormal = SMToAngle(acosf(SMVector3Dot(-vDir, vNormal))); + + if(m_isBursting && fAngleDirNormal > 87.0f) + { + fChance = 0.0f; + } + else + { + fChance += (1.0f - pow(0.9f, m_fArmorPiercing)) * 0.4f + (1.0f - pow(0.9f, fDurability)) * 0.4f; + } + + if(fAngleDirNormal > 80.0f) + { + fXangle = (1.0f - pow(0.99f, fDensity)) * 45.0f * (true /* RIFLE_TYPE == RIFLE_TYPE_RIGHT */ ? 1.0f : -1.0f); // RIFLE_TYPE_UNRIFLED : 0.0f + // @FIXME: consider m_fRifleStep too + } + //else if(fAngleDirNormal < 10.0f) + { + fChance += (1.0f - pow(0.9f, fDensity)) * 0.5f; + if(canHole(fDurability, fSpeed, pfNewSpeed)) + { + fChance = 0.0f; + isNewSpeedSet = true; + } + else + { + fChance += 0.05f; + } + } + + if(m_isExpansive) + { + fChance = 0.0f; + } + + fChance *= 0.1f; + + bool bRecochet = randf(0.0f, 1.0f) < fChance; + + if(bRecochet) + { + *pvNewDir = SMQuaternion(SMVector3Cross(vDir, vNormal), SMToRadian(fAngleDirNormal)) * SMQuaternion(vNormal, fXangle) * vNormal; + } + else + { + *pvNewDir = vDir; + } + + if(!isNewSpeedSet) + { + if(bRecochet) + { + *pfNewSpeed = fSpeed; + //if(fXangle > 0.0f) + { + *pfNewSpeed *= 0.9f; + } + } + else + { + *pfNewSpeed = 0.0f; + } + } + + //pvNewDir + //pfNewSpeed + + return(bRecochet); +} + +bool CBaseAmmo::canHole(float fDurability, float fCurrentSpeed, float *pfNewSpeed) +{ + // based on m_fNextBarrierDepth + + if(m_fNextBarrierDepth < SIMD_EPSILON) + { + //*pfNewSpeed = fCurrentSpeed; + //return(true); + m_fNextBarrierDepth = 0.001f; + } + + float fCurrentEnergy = m_fBulletMass * 0.001f * fCurrentSpeed * fCurrentSpeed / 2.0f; + + float fRequiredEnergy = fDurability * m_fNextBarrierDepth * 100.0f; + + + fCurrentEnergy -= fRequiredEnergy; + + if(fCurrentEnergy >= 0.0f) + { + *pfNewSpeed = sqrtf(fCurrentEnergy * 2.0f / (m_fBulletMass * 0.001f)); + return(true); + } + + *pfNewSpeed = 0.0f; + return(false); +} + +float CBaseAmmo::getStartSpeed() const +{ + return(m_fStartSpeed); +} \ No newline at end of file diff --git a/source/game/BaseAmmo.h b/source/game/BaseAmmo.h index cb706c3bb..c7524e22f 100644 --- a/source/game/BaseAmmo.h +++ b/source/game/BaseAmmo.h @@ -13,6 +13,10 @@ See the license in LICENSE #define __BASE_AMMO_H #include "BaseSupply.h" +#include "BaseCharacter.h" + +#define BULLET_MAX_JUMPS 32 +#define BULLET_STEP_DISTANCE 5.0f /* 5 метров */ /*! Базовый класс патронов \ingroup cbaseitem @@ -25,7 +29,14 @@ public: DECLARE_CONSTRUCTOR(); //! Стреляет пулю - void fire(const float3 &vStart, const float3 &vEnd); + void fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker=NULL); + + bool isAmmo() const + { + return(true); + } + + float getStartSpeed() const; protected: @@ -35,6 +46,34 @@ protected: float m_fBulletMass; //! Бронебойность float m_fArmorPiercing; + //! Экспансивная? + bool m_isExpansive; + //! Разрывная? + bool m_isBursting; + + struct HitPoint + { + float3_t vPosition; + float3_t vNormal; + const btCollisionObject *pCollisionObject; + float fFraction; + bool isExit; + btCollisionWorld::LocalShapeInfo shapeInfo; + }; + + //! Рисует декаль в точке попадания + void shootDecal(const float3 &vPos, const float3 &vNormal, ID idMtl); + + //! Определяет, был ли рикошет + bool shouldRecochet(const float3 &vPos, const float3 &vNormal, const float3 &vDir, ID idMtl, float fSpeed, float3 *pvNewDir, float *pfNewSpeed); + + //! Определяет, может ли пуля пробить препятствие + bool canHole(float fDurability, float fCurrentSpeed, float *pfNewSpeed); + + //! Хранит толщину препятствия во время расчета выстрела. Изменяется во время полета от препятствия к препятствию + float m_fNextBarrierDepth; + + void fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker, float fSpeed); }; #endif diff --git a/source/game/BaseAnimating.h b/source/game/BaseAnimating.h index 289d4e76e..9ed6eb6e9 100644 --- a/source/game/BaseAnimating.h +++ b/source/game/BaseAnimating.h @@ -48,7 +48,7 @@ public: bool playingAnimations(const char* name); void setPos(const float3 & pos); void setOrient(const SMQuaternion & q); - + protected: IAnimPlayer * m_pAnimPlayer; const char * m_szModelFile; @@ -56,7 +56,7 @@ protected: virtual void initPhysics(); virtual void createPhysBody(); - void releasePhysics(); + virtual void releasePhysics(); virtual void removePhysBody(); btCollisionShape * m_pCollideShape; diff --git a/source/game/BaseCharacter.cpp b/source/game/BaseCharacter.cpp index 3508cbb84..85c53176d 100644 --- a/source/game/BaseCharacter.cpp +++ b/source/game/BaseCharacter.cpp @@ -48,7 +48,8 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr): m_uMoveDir(PM_OBSERVER), m_vPitchYawRoll(float3_t(0, 0, 0)), m_pActiveTool(NULL), - m_fCurrentSpread(0.0f) + m_fCurrentSpread(0.0f), + m_pHitboxBodies(NULL) { btTransform startTransform; startTransform.setIdentity(); @@ -73,9 +74,9 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr): m_pCharacter->setFallSpeed(300.0f); //m_pCharacter->setFallSpeed(30.0f); - SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::DebrisFilter); + SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_CHARACTER, CG_ALL & ~(CG_DEBRIS | CG_HITBOX | CG_WATER)); - m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); + //m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); SXPhysics_GetDynWorld()->addAction(m_pCharacter); @@ -90,14 +91,18 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr): m_flashlight->setColor(float3(3.5, 3.5, 3.5)); //m_flashlight->setShadowType(-1); m_flashlight->setShadowType(1); + m_flashlight->setEnable(false); m_idTaskSpread = SET_INTERVAL(updateSpread, 1.0f / 30.0f); + + m_pInventory = new CCharacterInventory(this); } CBaseCharacter::~CBaseCharacter() { CLEAR_INTERVAL(m_idTaskSpread); REMOVE_ENTITY(m_flashlight); + mem_delete(m_pInventory); } @@ -148,10 +153,9 @@ void CBaseCharacter::nextFireMode() { return; } - if(m_pActiveTool) + if(m_pActiveTool && m_pActiveTool->isWeapon()) { - //@FIXME: Add correct call - //m_pActiveTool->nextFireMode(); + ((CBaseWeapon*)m_pActiveTool)->nextFireMode(); } } @@ -171,7 +175,7 @@ void CBaseCharacter::playFootstepsSound() btKinematicClosestNotMeRayResultCallback cb(m_pGhostObject, F3_BTVEC(start), F3_BTVEC(end)); SXPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb); - if(cb.hasHit() && cb.m_shapeInfo.m_shapePart == 0 && cb.m_shapeInfo.m_triangleIndex >= 0) + if(cb.hasHit()/* && cb.m_shapeInfo.m_shapePart == 0 && cb.m_shapeInfo.m_triangleIndex >= 0*/) { MTLTYPE_PHYSIC type = (MTLTYPE_PHYSIC)SXPhysics_GetMtlType(cb.m_collisionObject, &cb.m_shapeInfo); g_pGameData->playFootstepSound(type, BTVEC_F3(cb.m_hitPointWorld)); @@ -249,3 +253,131 @@ float CBaseCharacter::getCurrentSpread() { return(m_fCurrentSpread); } + +void CBaseCharacter::initHitboxes() +{ + if(!m_pAnimPlayer) + { + return; + } + + int l = m_pAnimPlayer->getHitboxCount(); + m_pHitboxBodies = new btRigidBody*[l]; + + const ModelHitbox * hb; + for(int i = 0; i < l; ++i) + { + hb = m_pAnimPlayer->getHitbox(i); + btCollisionShape *pShape; + switch(hb->type) + { + case HT_BOX: + pShape = new btBoxShape(F3_BTVEC(hb->lwh * 0.5f * m_fBaseScale)); + break; + case HT_CAPSULE: + pShape = new btCapsuleShape(hb->lwh.y * 0.5f * m_fBaseScale, hb->lwh.z * m_fBaseScale); + break; + case HT_CYLINDER: + pShape = new btCylinderShape(F3_BTVEC(hb->lwh * 0.5f * m_fBaseScale)); + break; + case HT_ELIPSOID: + // @FIXME: Add actual elipsoid shape + pShape = new btSphereShape(hb->lwh.x); + break; + case HT_CONVEX: + assert(false && "Not supported here"); + } + btVector3 vInertia; + const float fMass = 1.0f; + pShape->calculateLocalInertia(fMass, vInertia); + + btDefaultMotionState * motionState = new btDefaultMotionState(); + + btRigidBody::btRigidBodyConstructionInfo rigidBodyCI( + fMass, // mass + motionState, // initial position + pShape, // collision shape of body + vInertia // local inertia + ); + btRigidBody * pRigidBody = new btRigidBody(rigidBodyCI); + pRigidBody->setUserPointer(this); + + pRigidBody->setAngularFactor(0.0f); + pRigidBody->setLinearFactor(btVector3(0.0f, 0.0f, 0.0f)); + + SXPhysics_AddShapeEx(pRigidBody, CG_HITBOX, CG_BULLETFIRE); + m_pHitboxBodies[i] = pRigidBody; + } + + updateHitboxes(); +} + +void CBaseCharacter::updateHitboxes() +{ + if(!m_pAnimPlayer || !m_pHitboxBodies) + { + return; + } + + const ModelHitbox * hb; + for(int i = 0, l = m_pAnimPlayer->getHitboxCount(); i < l; ++i) + { + hb = m_pAnimPlayer->getHitbox(i); + + //SMMATRIX mBone = m_pAnimPlayer->getBoneTransformPos(hb->bone_id); + + m_pHitboxBodies[i]->getWorldTransform().setFromOpenGLMatrix((btScalar*)&(SMMatrixRotationX(hb->rot.x) + * SMMatrixRotationY(hb->rot.y) + * SMMatrixRotationZ(hb->rot.z) + * SMMatrixTranslation(hb->pos * m_fBaseScale) + * m_pAnimPlayer->getBoneTransform(hb->bone_id, true) + * getWorldTM() + )); + } +} + +void CBaseCharacter::releaseHitboxes() +{ + if(!m_pAnimPlayer || !m_pHitboxBodies) + { + return; + } + + for(int i = 0, l = m_pAnimPlayer->getHitboxCount(); i < l; ++i) + { + SXPhysics_RemoveShape(m_pHitboxBodies[i]); + + btMotionState * motionState = m_pHitboxBodies[i]->getMotionState(); + + mem_delete(motionState); + + btCollisionShape * pShape = m_pHitboxBodies[i]->getCollisionShape(); + mem_delete(pShape); + mem_delete(m_pHitboxBodies[i]); + } + + mem_delete_a(m_pHitboxBodies); +} + +void CBaseCharacter::onSync() +{ + BaseClass::onSync(); + + updateHitboxes(); +} + +void CBaseCharacter::initPhysics() +{ + initHitboxes(); +} + +void CBaseCharacter::releasePhysics() +{ + releaseHitboxes(); +} + +/*void CBaseCharacter::dispatchDamage(CTakeDamageInfo &takeDamageInfo) +{ + // adjust damage by bodypart + BaseClass::dispatchDamage(takeDamageInfo); +}*/ diff --git a/source/game/BaseCharacter.h b/source/game/BaseCharacter.h index 75009b222..9b096eb2f 100644 --- a/source/game/BaseCharacter.h +++ b/source/game/BaseCharacter.h @@ -18,6 +18,7 @@ See the license in LICENSE #include "BaseAnimating.h" #include "LightDirectional.h" +#include "CharacterInventory.h" class CBaseTool; @@ -68,6 +69,26 @@ public: //! �������� ������������ ��� �������� ������ ����������� �������� (� ������ �������� ��������) float getCurrentSpread(); + btCollisionObject *getBtCollisionObject() const + { + return(m_pGhostObject); + } + void initHitboxes(); + void releaseHitboxes(); + void updateHitboxes(); + + void onSync(); + + void initPhysics(); + void releasePhysics(); + + //void dispatchDamage(CTakeDamageInfo &takeDamageInfo); + + CCharacterInventory * getInventory() + { + return(m_pInventory); + } + protected: //! ������� CLightDirectional* m_flashlight; @@ -83,6 +104,7 @@ protected: btRigidBody * m_pRigidBody; btPairCachingGhostObject * m_pGhostObject; btKinematicCharacterController * m_pCharacter; + btRigidBody ** m_pHitboxBodies; //! @} //! ���� �������� ������ @@ -99,6 +121,10 @@ protected: //! ����������� �������� �������� float m_fCurrentSpread; + + CCharacterInventory * m_pInventory; + + }; #endif diff --git a/source/game/BaseEntity.cpp b/source/game/BaseEntity.cpp index 40ddce8f2..1101d3ab0 100644 --- a/source/game/BaseEntity.cpp +++ b/source/game/BaseEntity.cpp @@ -27,6 +27,8 @@ BEGIN_PROPTABLE_NOBASE(CBaseEntity) DEFINE_FIELD_FLAGS(m_iFlags, 0, "flags", "Flags", EDITOR_FLAGS) //! Объект-владелец DEFINE_FIELD_ENTITY(m_pOwner, PDFF_NOEXPORT | PDFF_NOEDIT, "owner", "", EDITOR_NONE) + //! Здоровье + DEFINE_FIELD_FLOAT(m_fHealth, PDFF_NOEXPORT | PDFF_NOEDIT, "health", "", EDITOR_NONE) //DEFINE_FIELD_STRING(m_szName, 0, "some opt", "Option", EDITOR_COMBOBOX) // COMBO_OPTION("Option 1", "value 1") @@ -62,7 +64,8 @@ CBaseEntity::CBaseEntity(CEntityManager * pWorld): m_szName(NULL), m_pParent(NULL), m_iParentAttachment(-1), - m_pOwner(NULL)/*, + m_pOwner(NULL), + m_fHealth(100.0f)/*, m_vDiscreteLinearVelocity(float3_t(0.0f, 0.0f, 0.0f))*/ { m_iId = pWorld->reg(this); @@ -644,4 +647,37 @@ void CBaseEntity::updateOutputs() } pt = pt->pBaseProptable; } -} \ No newline at end of file +} + +void CBaseEntity::dispatchDamage(CTakeDamageInfo &takeDamageInfo) +{ + float fHealth = takeDamageInfo.m_fDamage * 0.1f; + if(takeDamageInfo.m_pInflictor) + { + LibReport(REPORT_MSG_LEVEL_NOTICE, "%s damaged (" COLOR_LRED "%.2f" COLOR_RESET ") by " COLOR_YELLOW "%s\n", getClassName(), fHealth, takeDamageInfo.m_pInflictor->getClassName()); + } + else + { + LibReport(REPORT_MSG_LEVEL_NOTICE, "%s damaged (" COLOR_LRED "%.2f" COLOR_RESET ")\n", getClassName(), fHealth); + } + takeHealth(fHealth); +} + +void CBaseEntity::takeHealth(float fVal) +{ + if(m_fHealth <= 0.0f) + { + return; + } + m_fHealth -= fVal; + if(m_fHealth <= 0.0f) + { + onDeath(); + } +} + +void CBaseEntity::onDeath() +{ + LibReport(REPORT_MSG_LEVEL_NOTICE, "Entity %s died!\n", getClassName()); + // do nothing +} diff --git a/source/game/BaseEntity.h b/source/game/BaseEntity.h index 30a24e916..24195cf66 100644 --- a/source/game/BaseEntity.h +++ b/source/game/BaseEntity.h @@ -27,6 +27,8 @@ See the license in LICENSE #include "proptable.h" +#include "TakeDamageInfo.h" + #pragma pointers_to_members(full_generality, virtual_inheritance) #pragma warning(push) @@ -99,6 +101,10 @@ public: //void updateDiscreteLinearVelocity(int step, float dt); //const float3_t & getDiscreteLinearVelocity() const; + virtual void dispatchDamage(CTakeDamageInfo &takeDamageInfo); + + virtual void onDeath(); + private: void setClassName(const char * name); void setDefaults(); @@ -162,6 +168,11 @@ protected: \note только для внутреннего использования */ void updateOutputs(); + + //! здоровье [0,+inf] + float m_fHealth; + + void takeHealth(float fVal); }; #pragma warning(pop) diff --git a/source/game/BaseItem.cpp b/source/game/BaseItem.cpp index 572fc8414..b79eb9ff1 100644 --- a/source/game/BaseItem.cpp +++ b/source/game/BaseItem.cpp @@ -31,7 +31,7 @@ CBaseItem::CBaseItem(CEntityManager * pMgr): BaseClass(pMgr), m_bInvStackable(true), m_iInvStackCurSize(0), - m_iInvStackMaxSize(0), + m_iInvStackMaxSize(1), m_iInvWeight(0.0f), m_bPickable(true) { diff --git a/source/game/BaseMag.cpp b/source/game/BaseMag.cpp index 89a969c8f..a78317531 100644 --- a/source/game/BaseMag.cpp +++ b/source/game/BaseMag.cpp @@ -40,4 +40,8 @@ int CBaseMag::getCapacity() void CBaseMag::load(int count) { m_iCurrentLoad += count; + if(m_iCurrentLoad > m_iCapacity) + { + m_iCurrentLoad = m_iCapacity; + } } diff --git a/source/game/BaseSupply.h b/source/game/BaseSupply.h index e95af1a0a..290b24843 100644 --- a/source/game/BaseSupply.h +++ b/source/game/BaseSupply.h @@ -23,6 +23,11 @@ class CBaseSupply: public CBaseItem DECLARE_PROPTABLE(); public: DECLARE_TRIVIAL_CONSTRUCTOR(); + + virtual bool isAmmo() const + { + return(false); + } }; #endif diff --git a/source/game/BaseTool.cpp b/source/game/BaseTool.cpp index 13eab5f92..af21ecfa2 100644 --- a/source/game/BaseTool.cpp +++ b/source/game/BaseTool.cpp @@ -46,6 +46,8 @@ BEGIN_PROPTABLE(CBaseTool) DEFINE_FIELD_FLOAT(m_fMaxDistance, PDFF_NOEDIT | PDFF_NOEXPORT, "max_distance", "", EDITOR_NONE) //! Подходящие типы припасов, классы, через запятую DEFINE_FIELD_STRING(m_szUsableAmmos, PDFF_NOEDIT | PDFF_NOEXPORT, "ammos", "", EDITOR_NONE) + //! Класс заряженного в данный момент припаса + DEFINE_FIELD_STRING(m_szLoadedAmmo, PDFF_NOEDIT | PDFF_NOEXPORT, "loaded_ammo", "", EDITOR_NONE) END_PROPTABLE() @@ -66,7 +68,8 @@ CBaseTool::CBaseTool(CEntityManager * pMgr): m_iMuzzleFlash(-1), m_iMuzzleFlash2(-1), m_fMaxDistance(1000.0f), - m_bIsWeapon(false) + m_bIsWeapon(false), + m_pLoadedAmmo(NULL) { m_bInvStackable = false; @@ -107,7 +110,7 @@ void CBaseTool::setNextUse(float time) } bool CBaseTool::canUse() { - return(m_bCanUse); + return(m_bCanUse && !m_bInPrimaryAction); } void CBaseTool::primaryAction(BOOL st) @@ -284,3 +287,51 @@ float CBaseTool::getCondition() const { return(1.0f); } + +CBaseSupply *CBaseTool::getAmmo() const +{ + return(m_pLoadedAmmo); +} + +void CBaseTool::chargeAmmo(CBaseSupply *pAmmo) +{ + if(!pAmmo || !isValidAmmo(pAmmo)) + { + return; + } + if(getAmmo()) + { + uncharge(); + } + m_pLoadedAmmo = pAmmo; + m_pLoadedAmmo->setParent(this); + _setStrVal(&m_szLoadedAmmo, m_pLoadedAmmo->getClassName()); +} + +void CBaseTool::uncharge() +{ + if(!getAmmo()) + { + return; + } + _setStrVal(&m_szLoadedAmmo, ""); + m_pLoadedAmmo->setParent(NULL); + //getOwner()->getInventory()->put(getAmmo()); + m_pLoadedAmmo = NULL; +} + +bool CBaseTool::isValidAmmo(CBaseSupply *pAmmo) +{ + const char * str = strstr(m_szUsableAmmos, pAmmo->getClassName()); + if(str) + { + char chr = str[strlen(pAmmo->getClassName())]; + return(chr == ',' || chr == 0); + } + return(false); +} + +float CBaseTool::getMaxDistance() const +{ + return(m_fMaxDistance); +} diff --git a/source/game/BaseTool.h b/source/game/BaseTool.h index 18b2e0cf6..d5c9edc4a 100644 --- a/source/game/BaseTool.h +++ b/source/game/BaseTool.h @@ -13,6 +13,7 @@ See the license in LICENSE #define __BASE_TOOL_H #include "BaseItem.h" +#include "BaseSupply.h" #include <score/sxscore.h> enum @@ -65,8 +66,19 @@ public: //! Состояние: 1 - целое; 0 - сломанное float getCondition() const; + //! Объект заряженного припаса + CBaseSupply *getAmmo() const; + //! Зарядить + void chargeAmmo(CBaseSupply *pAmmo); + //! Разрядить + void uncharge(); + + float getMaxDistance() const; + protected: + bool isValidAmmo(CBaseSupply *pAmmo); + bool m_bInPrimaryAction; bool m_bInSecondaryAction; @@ -110,6 +122,8 @@ protected: const char * m_szSecondaryActionMuzzleflash; const char * m_szUsableAmmos; + const char * m_szLoadedAmmo; + CBaseSupply * m_pLoadedAmmo; float m_fMaxDistance; diff --git a/source/game/BaseTrigger.cpp b/source/game/BaseTrigger.cpp index b73b78ddb..84b5316c7 100644 --- a/source/game/BaseTrigger.cpp +++ b/source/game/BaseTrigger.cpp @@ -64,7 +64,7 @@ void CBaseTrigger::enable() m_idUpdateInterval = SET_INTERVAL(update, 0); if(m_pGhostObject) { - SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::CharacterFilter); + SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_TRIGGER, CG_CHARACTER); } } } @@ -115,7 +115,7 @@ void CBaseTrigger::createPhysBody() m_pGhostObject->setCollisionShape(m_pCollideShape); m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() ^ btCollisionObject::CF_NO_CONTACT_RESPONSE); - SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::CharacterFilter); + SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_TRIGGER, CG_CHARACTER); } } diff --git a/source/game/BaseWeapon.cpp b/source/game/BaseWeapon.cpp index 9dc7dd01e..cd5fcca5c 100644 --- a/source/game/BaseWeapon.cpp +++ b/source/game/BaseWeapon.cpp @@ -7,6 +7,8 @@ See the license in LICENSE #include <particles/sxparticles.h> #include "BaseWeapon.h" #include "Player.h" +#include "BaseAmmo.h" +#include "Random.h" /*! \skydocent base_weapon Базовый класс для оружия @@ -26,11 +28,11 @@ BEGIN_PROPTABLE(CBaseWeapon) //! Доступные режимы стрельбы DEFINE_FIELD_STRING(m_szFireModes, PDFF_NOEDIT | PDFF_NOEXPORT, "fire_modes", "", EDITOR_NONE) //! Скорострельность одиночными - DEFINE_FIELD_INT(m_iSingleSpeed, PDFF_NOEDIT | PDFF_NOEXPORT, "single_speed", "", EDITOR_NONE) + DEFINE_FIELD_INT(m_iSingleRate, PDFF_NOEDIT | PDFF_NOEXPORT, "single_rate", "", EDITOR_NONE) //! Скорострельность в автоматическом режиме - DEFINE_FIELD_INT(m_iBurstSpeed, PDFF_NOEDIT | PDFF_NOEXPORT, "burst_speed", "", EDITOR_NONE) + DEFINE_FIELD_INT(m_iBurstRate, PDFF_NOEDIT | PDFF_NOEXPORT, "burst_rate", "", EDITOR_NONE) //! Скорострельность отсечками - DEFINE_FIELD_INT(m_iCutoffSpeed, PDFF_NOEDIT | PDFF_NOEXPORT, "cutoff_speed", "", EDITOR_NONE) + DEFINE_FIELD_INT(m_iCutoffRate, PDFF_NOEDIT | PDFF_NOEXPORT, "cutoff_rate", "", EDITOR_NONE) //! Патронов в отсечке DEFINE_FIELD_INT(m_iCutoffSize, PDFF_NOEDIT | PDFF_NOEXPORT, "cutoff_size", "", EDITOR_NONE) //! Текущий режим стрельбы @@ -78,12 +80,23 @@ BEGIN_PROPTABLE(CBaseWeapon) DEFINE_FIELD_FLOAT(m_fSpreadArm, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_arm", "", EDITOR_NONE) //! коэффициент разброса в прицеливании DEFINE_FIELD_FLOAT(m_fSpreadIronSight, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_ironsight", "", EDITOR_NONE) + + //! Дальность пристрелки + DEFINE_FIELD_FLOAT(m_fAimingRange, PDFF_NOEDIT | PDFF_NOEXPORT, "aiming_range", "", EDITOR_NONE) + + //! тип нарезки ствола: 0 - гладкоствольное; -1 - левая; 1 - правая + DEFINE_FIELD_INT(m_rifleType, PDFF_NOEDIT | PDFF_NOEXPORT, "rifle_type", "", EDITOR_NONE) + //! шаг нарезки ствола (мм) + DEFINE_FIELD_FLOAT(m_fRifleStep, PDFF_NOEDIT | PDFF_NOEXPORT, "rifle_step", "", EDITOR_NONE) END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseWeapon, base_weapon); CBaseWeapon::CBaseWeapon(CEntityManager * pMgr): BaseClass(pMgr), + + m_idTaskShoot(-1), + m_pSilencer(NULL), m_pScope(NULL), m_pHandle(NULL), @@ -110,7 +123,9 @@ CBaseWeapon::CBaseWeapon(CEntityManager * pMgr): m_fSpreadAirborne(5.0f), m_fSpreadCondition(3.0f), m_fSpreadArm(3.0f), - m_fSpreadIronSight(-0.8f) + m_fSpreadIronSight(-0.8f), + + m_fAimingRange(100.f) { m_bIsWeapon = true; } @@ -189,38 +204,39 @@ bool CBaseWeapon::setKV(const char * name, const char * value) void CBaseWeapon::primaryAction(BOOL st) { - m_bInPrimaryAction = st != FALSE; + //m_bInPrimaryAction = st != FALSE; + if(st) { - playAnimation("shoot1"); - if(ID_VALID(m_iMuzzleFlash)) + if(canUse()) { - SPE_EffectEnableSet(m_iMuzzleFlash, true); - } - if(ID_VALID(m_iSoundAction1)) - { - SSCore_SndInstancePlay3d(m_iSoundAction1, &getPos()); + m_bInPrimaryAction = true; + switch(m_fireMode) + { + case FIRE_MODE_BURST: + m_idTaskShoot = SET_INTERVAL(taskShoot, 60.0f / (float)m_iBurstRate); + break; + case FIRE_MODE_CUTOFF: + m_iCutoffCurrent = 0; + m_idTaskShoot = SET_INTERVAL(taskShoot, 60.0f / (float)m_iCutoffRate); + break; + case FIRE_MODE_SINGLE: + setNextUse(60.0f / (float)m_iSingleRate); + break; + } + taskShoot(0.0f); } - - //((CPlayer*)m_pOwner)->is - - //trace line - float3 start = getPos(); - float3 dir = m_pParent->getOrient() * float3(0.0f, 0.0f, 1.0f); - float3 end = start + dir * m_fMaxDistance; - btCollisionWorld::ClosestRayResultCallback cb(F3_BTVEC(start), F3_BTVEC(end)); - SXPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb); - - if(cb.hasHit()) + } + else + { + if(m_fireMode != FIRE_MODE_CUTOFF) { - //shoot decal - //SXDecals_ShootDecal(DECAL_TYPE_CONCRETE, BTVEC_F3(cb.m_hitPointWorld), BTVEC_F3(cb.m_hitNormalWorld)); - SPE_EffectPlayByName("fire", &BTVEC_F3(cb.m_hitPointWorld), &BTVEC_F3(cb.m_hitNormalWorld)); - if(!cb.m_collisionObject->isStaticOrKinematicObject()) + if(ID_VALID(m_idTaskShoot)) { - ((btRigidBody*)cb.m_collisionObject)->applyCentralImpulse(F3_BTVEC(dir * 10.0f)); - cb.m_collisionObject->activate(); + CLEAR_INTERVAL(m_idTaskShoot); + m_idTaskShoot = -1; } + m_bInPrimaryAction = false; } } } @@ -248,27 +264,53 @@ void CBaseWeapon::reload() } if(canUse()) { - //int count = m_pOwner->getInventory()->consumeItems("ammo_5.45x39ps", m_pMag->getCapacity() - m_pMag->getLoad() + m_iCapacity - m_iCurrentLoad); - //count += m_iCurrentLoad; - //m_iCurrentLoad = min(count, m_iCapacity); - //count -= m_iCurrentLoad; - //m_pMag->load(count); - - setNextUse(m_fReloadTime); - playAnimation("reload"); - if(ID_VALID(m_idSndReload)) + int iWantLoad = m_pMag->getCapacity() - m_pMag->getLoad()/* + m_iCapacity - m_iCurrentLoad */; + if(iWantLoad <= 0) + { + printf(COLOR_MAGENTA "Mag full!\n" COLOR_RESET); + return; + } + int count = ((CBaseCharacter*)m_pOwner)->getInventory()->consumeItems(m_szLoadedAmmo, iWantLoad); + if(count) + { + bool isFast = m_iCapacity == m_iCurrentLoad; + + count += m_iCurrentLoad; + m_iCurrentLoad = min(count, m_iCapacity); + count -= m_iCurrentLoad; + m_pMag->load(count); + + setNextUse(m_fReloadTime); + playAnimation(isFast ? "reload_fast" : "reload"); + if(isFast) + { + /*if(ID_VALID(m_idSndReloadFast)) + { + SSCore_SndInstancePlay3d(m_idSndReloadFast, &getPos()); + }*/ + } + else + { + if(ID_VALID(m_idSndReload)) + { + SSCore_SndInstancePlay3d(m_idSndReload, &getPos()); + } + } + } + else { - SSCore_SndInstancePlay3d(m_idSndReload, &getPos()); + printf(COLOR_MAGENTA "No more bullets!\n" COLOR_RESET); + return; } } } void CBaseWeapon::setFireMode(FIRE_MODE mode) { - if(!(m_iFireModes & mode)) + if((m_iFireModes & mode) && canUse()) { m_fireMode = mode; - if(ID_VALID(m_idSndReload)) + if(ID_VALID(m_idSndSwitch)) { SSCore_SndInstancePlay3d(m_idSndSwitch, &getPos()); } @@ -286,7 +328,7 @@ void CBaseWeapon::nextFireMode() while(newMode != cur && !(m_iFireModes & (1 << newMode))); if(newMode != cur) { - setFireMode((FIRE_MODE)newMode); + setFireMode((FIRE_MODE)(1 << newMode)); } } @@ -340,3 +382,128 @@ float CBaseWeapon::getSpreadCoeff(SPREAD_COEFF what) const } return(1.0f); } + +float3 CBaseWeapon::applySpread(const float3 &vDir, float fSpread) +{ + float3 vRight, vUp; + + if(vDir.x == 0.0f && vDir.y == 0.0f) + { + vRight = float3(0.0f, -1.0f, 0.0f); + vUp = float3(-vDir.z, 0.0f, 0.0f); + } + else + { + vRight = SMVector3Normalize(SMVector3Cross(vDir, float3((0.0f, 0.0f, 1.0f)))); + vUp = SMVector2Normalize(SMVector3Cross(vRight, vDir)); + } + + + + float x, y, z; + const float flatness = 0.5f; + CRandom random; + + do + { + x = random.getRandomFloat(-1, 1) * flatness + random.getRandomFloat(-1, 1) * (1 - flatness); + y = random.getRandomFloat(-1, 1) * flatness + random.getRandomFloat(-1, 1) * (1 - flatness); + + z = x*x + y*y; + } + while(z > 1); + + fSpread = tanf(fSpread); + + return(vDir + x * fSpread * vRight + y * fSpread * vUp); +} + +void CBaseWeapon::taskShoot(float dt) +{ + if(m_fireMode == FIRE_MODE_CUTOFF) + { + ++m_iCutoffCurrent; + if(m_iCutoffCurrent > m_iCutoffSize) + { + if(ID_VALID(m_idTaskShoot)) + { + CLEAR_INTERVAL(m_idTaskShoot); + m_idTaskShoot = -1; + } + m_bInPrimaryAction = false; + return; + } + } + + CBaseAmmo *pAmmo = NULL; + if(canShoot() && getAmmo() && getAmmo()->isAmmo()) + { + pAmmo = (CBaseAmmo*)getAmmo(); + } + else + { + if(ID_VALID(m_idSndEmpty)) + { + SSCore_SndInstancePlay3d(m_idSndEmpty, &getPos()); + } + if(ID_VALID(m_idTaskShoot)) + { + CLEAR_INTERVAL(m_idTaskShoot); + m_idTaskShoot = -1; + } + m_bInPrimaryAction = false; + return; + } + + playAnimation("shoot1"); + if(ID_VALID(m_iMuzzleFlash)) + { + SPE_EffectEnableSet(m_iMuzzleFlash, true); + } + if(ID_VALID(m_idSndShoot)) + { + SSCore_SndInstancePlay3d(m_idSndShoot, &getPos()); + } + + //((CPlayer*)m_pOwner)->is + + //trace line + float3 start = getPos(); + float3 dir = m_pParent->getOrient() * float3(0.0f, 0.0f, 1.0f); + + dir = SMQuaternion(m_pParent->getOrient() * float3(1.0f, 0.0f, 0.0f), asinf(m_fAimingRange * 10.0f / (pAmmo->getStartSpeed() * pAmmo->getStartSpeed())) * 0.5f) * dir; + + + dir = applySpread(dir, SMToRadian(((CBaseCharacter*)getOwner())->getCurrentSpread())); + + pAmmo->fire(start, dir, (CBaseCharacter*)getOwner()); + + if(m_pMag && m_pMag->getLoad() > 0) + { + m_pMag->load(-1); + } + else + { + --m_iCurrentLoad; + } +} + +void CBaseWeapon::attachMag(CBaseMag * pMag) +{ + m_pMag = pMag; + + int iNeedLoad = m_iCapacity - m_iCurrentLoad; + if(iNeedLoad > 0) + { + if(m_pMag->getLoad() >= iNeedLoad) + { + m_iCurrentLoad += iNeedLoad; + m_pMag->load(-iNeedLoad); + } + else + { + m_iCurrentLoad += m_pMag->getLoad(); + m_pMag->load(-m_pMag->getLoad()); + } + } +} diff --git a/source/game/BaseWeapon.h b/source/game/BaseWeapon.h index 0092c51a2..4400c1011 100644 --- a/source/game/BaseWeapon.h +++ b/source/game/BaseWeapon.h @@ -43,6 +43,16 @@ enum SPREAD_COEFF SPREAD_COEFF_IRONSIGHT, //!< в прицеливании }; +//! Тип нарезки ствола +enum RIFLE_TYPE +{ + RIFLE_TYPE_LEFT = -1, //!< Левая + RIFLE_TYPE_UNRIFLED = 0, //!< Гладкоствольное + RIFLE_TYPE_RIGHT = 1, //!< Правая + + RIFLE_TYPE_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +}; + /*! Оружие \ingroup cbaseitem */ @@ -78,8 +88,21 @@ public: //! Коэффициент разброса float getSpreadCoeff(SPREAD_COEFF what) const; + //! Тип нарезки ствола + RIFLE_TYPE getRifleType() const {return(m_rifleType);} + + //! Подсоединить магазин + void attachMag(CBaseMag * pMag); protected: + //! Распределение гаусса вектора vDir в телесном угле fSpread + float3 applySpread(const float3 &vDir, float fSpread); + + //! Задача стрельбы + void taskShoot(float dt); + + ID m_idTaskShoot; + // Compatible addons const char * m_szAddonScopes; const char * m_szAddonSilencers; @@ -96,11 +119,13 @@ protected: FIRE_MODE m_fireMode; int m_iFireModes; const char * m_szFireModes; - int m_iSingleSpeed; - int m_iBurstSpeed; - int m_iCutoffSpeed; + int m_iSingleRate; + int m_iBurstRate; + int m_iCutoffRate; int m_iCutoffSize; + int m_iCutoffCurrent; + // Sounds const char * m_szSndDraw; const char * m_szSndHolster; @@ -118,6 +143,9 @@ protected: // Shooting float m_fEffectiveDistance; + RIFLE_TYPE m_rifleType; + float m_fRifleStep; + float m_fAimingRange; // Without mag int m_iCapacity; diff --git a/source/game/CharacterInventory.cpp b/source/game/CharacterInventory.cpp new file mode 100644 index 000000000..af0a6c856 --- /dev/null +++ b/source/game/CharacterInventory.cpp @@ -0,0 +1,163 @@ +#include "CharacterInventory.h" + +#include "BaseCharacter.h" + +CCharacterInventory::CCharacterInventory(CBaseCharacter * pOwner, int iSlotCount): + m_pOwner(pOwner), + m_iSlotCount(iSlotCount) +{ + assert(iSlotCount > 0); + + m_ppSlots = new CBaseItem*[iSlotCount]; + memset(m_ppSlots, 0, sizeof(CBaseItem*) * iSlotCount); +} + +CCharacterInventory::~CCharacterInventory() +{ + for(int i = 0; i < m_iSlotCount; ++i) + { + if(m_ppSlots[i]) + { + REMOVE_ENTITY(m_ppSlots[i]); + } + } + mem_delete_a(m_ppSlots); +} + +bool CCharacterInventory::hasItems(const char * szClassName, int iCount) +{ + assert(iCount > 0); + + for(int i = 0; i < m_iSlotCount; ++i) + { + if(m_ppSlots[i] && !fstrcmp(m_ppSlots[i]->getClassName(), szClassName)) + { + iCount -= m_ppSlots[i]->m_iInvStackCurSize; + if(iCount <= 0) + { + return(true); + } + } + } + return(iCount <= 0); +} + +int CCharacterInventory::consumeItems(const char *szClassName, int iCount) +{ + assert(iCount > 0); + + int iConsumed = 0; + + for(int i = 0; i < m_iSlotCount; ++i) + { + if(m_ppSlots[i] && !fstrcmp(m_ppSlots[i]->getClassName(), szClassName)) + { + if(m_ppSlots[i]->m_iInvStackCurSize >= iCount) + { + iConsumed += iCount; + m_ppSlots[i]->m_iInvStackCurSize -= iCount; + if(m_ppSlots[i]->m_iInvStackCurSize <= 0) + { + REMOVE_ENTITY(m_ppSlots[i]); + m_ppSlots[i] = 0; + } + break; + } + else + { + iConsumed += m_ppSlots[i]->m_iInvStackCurSize; + iCount -= m_ppSlots[i]->m_iInvStackCurSize; + + REMOVE_ENTITY(m_ppSlots[i]); + m_ppSlots[i] = 0; + } + } + } + return(iConsumed); +} + +void CCharacterInventory::putItems(const char *szClassName, int iCount) +{ + assert(iCount > 0); + for(int i = 0; i < m_iSlotCount; ++i) + { + if(m_ppSlots[i] && !fstrcmp(m_ppSlots[i]->getClassName(), szClassName) && m_ppSlots[i]->m_bInvStackable) + { + int iCanAdd = m_ppSlots[i]->m_iInvStackMaxSize - m_ppSlots[i]->m_iInvStackCurSize; + if(iCanAdd > 0) + { + if(iCanAdd >= iCount) + { + m_ppSlots[i]->m_iInvStackCurSize += iCount; + iCount = 0; + break; + } + else + { + iCount -= iCanAdd; + m_ppSlots[i]->m_iInvStackCurSize += iCanAdd; + } + } + } + } + + if(iCount > 0) + { + for(int i = 0; i < m_iSlotCount; ++i) + { + if(!m_ppSlots[i]) + { + if((m_ppSlots[i] = (CBaseItem*)CREATE_ENTITY(szClassName, m_pOwner->getManager()))) + { + int iCanAdd = m_ppSlots[i]->m_iInvStackMaxSize - m_ppSlots[i]->m_iInvStackCurSize; + if(iCanAdd > 0) + { + if(iCanAdd >= iCount) + { + m_ppSlots[i]->m_iInvStackCurSize += iCount; + iCount = 0; + break; + } + else + { + iCount -= iCanAdd; + m_ppSlots[i]->m_iInvStackCurSize += iCanAdd; + } + } + } + else + { + break; + } + } + } + } +} + +int CCharacterInventory::getSlotCount() const +{ + return(m_iSlotCount); +} + +CBaseItem * CCharacterInventory::getSlot(int i) const +{ + assert(i >= 0 && i < m_iSlotCount); + + return(m_ppSlots[i]); +} + +float CCharacterInventory::getTotalWeight() const +{ + float fTotal = 0.0f; + + for(int i = 0; i < m_iSlotCount; ++i) + { + if(m_ppSlots[i]) + { + fTotal += m_ppSlots[i]->getWeight() * m_ppSlots[i]->m_iInvStackCurSize; + } + } + + return(fTotal); +} + diff --git a/source/game/CharacterInventory.h b/source/game/CharacterInventory.h new file mode 100644 index 000000000..02ba8ae98 --- /dev/null +++ b/source/game/CharacterInventory.h @@ -0,0 +1,32 @@ +#ifndef __CHARACTER_INVENTORY_H +#define __CHARACTER_INVENTORY_H + +#include "BaseItem.h" + +class CBaseCharacter; + +class CCharacterInventory +{ +public: + CCharacterInventory(CBaseCharacter * pOwner, int iSlotCount = 8 * 16); + ~CCharacterInventory(); + + bool hasItems(const char * szClassName, int iCount = 1); + int consumeItems(const char *szClassName, int iCount = 1); + + void putItems(const char *szClassName, int iCount = 1); + //void putItems(CBaseItem *pItem); + + int getSlotCount() const; + CBaseItem * getSlot(int i) const; + + float getTotalWeight() const; + +protected: + + CBaseCharacter * m_pOwner; + CBaseItem ** m_ppSlots; + int m_iSlotCount; +}; + +#endif diff --git a/source/game/GameData.cpp b/source/game/GameData.cpp index 7e8544891..05a35686e 100644 --- a/source/game/GameData.cpp +++ b/source/game/GameData.cpp @@ -11,6 +11,8 @@ See the license in LICENSE #include <score/sxscore.h> +#include "Tracer.h" + CPlayer * GameData::m_pPlayer; CPointCamera * GameData::m_pActiveCamera; @@ -19,6 +21,8 @@ CEntityManager * GameData::m_pMgr; CRagdoll * g_pRagdoll; IAnimPlayer * pl; +CTracer *g_pTracer; + GameData::GameData() { loadFoostepsSounds(); @@ -80,6 +84,7 @@ GameData::GameData() Core_0RegisterConcmdClsArg("+debug_slot_move", m_pPlayer, (SXCONCMDCLSARG)&CPlayer::_ccmd_slot_on); Core_0RegisterConcmdCls("-debug_slot_move", m_pPlayer, (SXCONCMDCLS)&CPlayer::_ccmd_slot_off); + g_pTracer = new CTracer(5000); //m_pPlayer->setModel("models/stalker_zombi/stalker_zombi_a.dse"); //m_pPlayer->playAnimation("reload"); @@ -93,6 +98,7 @@ GameData::~GameData() { //mem_delete(g_pRagdoll); + mem_delete(g_pTracer); mem_delete(m_pMgr); for(int i = 0; i < MPT_COUNT; ++i) @@ -108,6 +114,7 @@ void GameData::update() } void GameData::render() { + //g_pTracer->render(); } void GameData::renderHUD() { diff --git a/source/game/NPCBase.cpp b/source/game/NPCBase.cpp index 52090fdbe..e52e8bfca 100644 --- a/source/game/NPCBase.cpp +++ b/source/game/NPCBase.cpp @@ -17,10 +17,9 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CNPCBase, npc_base); -CNPCBase::CNPCBase(CEntityManager * pMgr) : +CNPCBase::CNPCBase(CEntityManager * pMgr): BaseClass(pMgr) { - m_fHealth = 1.f; m_fSpeedWalk = 0.07f; m_fSpeedRun = 0.12f; m_idCurrQuaidInPath = -1; @@ -44,29 +43,6 @@ CNPCBase::~CNPCBase() } -void CNPCBase::initPhysics() -{ - btTransform startTransform; - startTransform.setIdentity(); - startTransform.setOrigin(F3_BTVEC(m_vPosition)); - - m_pGhostObject = new btPairCachingGhostObject(); - m_pGhostObject->setWorldTransform(startTransform); - m_pCollideShape = new btCapsuleShape(0.3f, 1.4f); - m_pGhostObject->setCollisionShape(m_pCollideShape); - m_pGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); - m_pGhostObject->setUserPointer(this); - - m_pCharacter = new btKinematicCharacterController(m_pGhostObject, (btConvexShape*)m_pCollideShape, m_fStepHeight, btVector3(0.0f, 1.0f, 0.0f)); - m_pCharacter->setMaxJumpHeight(0.60f); - m_pCharacter->setJumpSpeed(4.50f); - m_pCharacter->setGravity(btVector3(0, -10.0f, 0)); - m_pCharacter->setFallSpeed(300.0f); - - SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::DebrisFilter); - SXPhysics_GetDynWorld()->addAction(m_pCharacter); -} - void CNPCBase::setPos(const float3 &pos) { float3 tpos = pos; @@ -131,7 +107,7 @@ ID CNPCBase::getAIQuad() bool CNPCBase::pathFind(ID endq) { - if (m_idCurrAiQuad >= 0 && SAIG_GridFindPath(m_idCurrAiQuad, endq)) + if(m_idCurrAiQuad >= 0 && SAIG_GridFindPath(m_idCurrAiQuad, endq)) { if (m_aPathQuads.size() > 0) SAIG_GridSetColorArr(&(m_aPathQuads[0]), 0, m_aPathQuads.size()); @@ -142,7 +118,7 @@ bool CNPCBase::pathFind(ID endq) m_vLastPathPos = m_vPosition; return true; } - + m_statePath = NPC_STATE_PATH_NOTFOUND; return false; } diff --git a/source/game/NPCBase.h b/source/game/NPCBase.h index 965376810..303daa135 100644 --- a/source/game/NPCBase.h +++ b/source/game/NPCBase.h @@ -16,7 +16,7 @@ See the license in LICENSE #ifndef __NPCBASE_H #define __NPCBASE_H -#include "BaseAnimating.h" +#include "BaseCharacter.h" #include <aigrid/sxaigrid.h> //! базовое направление для нпс @@ -58,9 +58,9 @@ enum NPC_STATE_PATH }; //! Базовый класс npc -class CNPCBase: public CBaseAnimating +class CNPCBase: public CBaseCharacter { - DECLARE_CLASS(CNPCBase, CBaseAnimating); + DECLARE_CLASS(CNPCBase, CBaseCharacter); DECLARE_PROPTABLE(); public: @@ -79,10 +79,8 @@ public: protected: - virtual void initPhysics(); - - btPairCachingGhostObject * m_pGhostObject; - btKinematicCharacterController * m_pCharacter; + //btPairCachingGhostObject * m_pGhostObject; + //btKinematicCharacterController * m_pCharacter; bool pathFind(ID endq); //!< поиск пути от текущего (на котором стоит нпс) до endq void pathWalk(); //!< хождение по пути @@ -91,9 +89,7 @@ protected: //! ориентаци нпс на точку pos, ttime время в млсек за которое нпс будет повернут в/на точку void orientAtPoint(const float3 *pos, DWORD ttime); void updateOrientLerp();//!< плавная интерполяция поворотов - - float m_fHealth; //!< здоровье [0,1] - + float m_fSpeedWalk; //!< скорость движения при ходьбе float m_fSpeedRun; //!< скорость движения при беге diff --git a/source/game/NPCZombie.cpp b/source/game/NPCZombie.cpp index d4ccd413c..560ff74aa 100644 --- a/source/game/NPCZombie.cpp +++ b/source/game/NPCZombie.cpp @@ -106,9 +106,9 @@ void CNPCZombie::randWalk() m_stateMove = NPC_STATE_MOVE_WALK; else if (m_stateMove != NPC_STATE_MOVE_IDLE) { - if (!playingAnimations("walk0")) + if (!playingAnimations("reload")) { - playAnimation("walk0"); + playAnimation("reload"); SSCore_SndPlay(m_idSndIdle2); } diff --git a/source/game/Player.cpp b/source/game/Player.cpp index f34cf7be3..f85ee7c91 100644 --- a/source/game/Player.cpp +++ b/source/game/Player.cpp @@ -10,6 +10,9 @@ See the license in LICENSE #include "LightDirectional.h" #include "BaseTool.h" #include <aigrid/sxaigrid.h> +#include "BaseAmmo.h" + +#include "BaseWeapon.h" #include "GameData.h" @@ -37,7 +40,6 @@ CPlayer::CPlayer(CEntityManager * pMgr): m_iUpdIval = SET_INTERVAL(updateInput, 0); - m_pActiveTool = (CBaseTool*)CREATE_ENTITY("weapon_ak74", m_pMgr); m_pActiveTool->setOwner(this); m_pActiveTool->attachHands(); @@ -46,9 +48,21 @@ CPlayer::CPlayer(CEntityManager * pMgr): m_pActiveTool->setOrient(getOrient()); m_pActiveTool->setParent(this); + CBaseAmmo *pAmmo = (CBaseAmmo*)CREATE_ENTITY("ammo_5.45x39ps", m_pMgr); + m_pActiveTool->chargeAmmo(pAmmo); + + CBaseMag *pMag = (CBaseMag*)CREATE_ENTITY("mag_ak74_30", m_pMgr); + pMag->load(30); + ((CBaseWeapon*)m_pActiveTool)->attachMag(pMag); + + getInventory()->putItems("ammo_5.45x39ps", 60); + + m_idQuadCurr = -1; m_pCrosshair = new CCrosshair(); + + m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); } CPlayer::~CPlayer() diff --git a/source/game/Random.h b/source/game/Random.h new file mode 100644 index 000000000..7fab77889 --- /dev/null +++ b/source/game/Random.h @@ -0,0 +1,21 @@ +#ifndef _RANDOM_H_ +#define _RANDOM_H_ + +#include <common/sxmath.h> + +/*! + ��������� ��������� ����� +*/ +class CRandom +{ +public: + CRandom(int iSeed=0) + { + } + float getRandomFloat(float fMinVal = 0.0f, float fMaxVal = 1.0f) + { + return(randf(fMinVal, fMaxVal)); + } +}; + +#endif diff --git a/source/game/TakeDamageInfo.h b/source/game/TakeDamageInfo.h new file mode 100644 index 000000000..563bc1afc --- /dev/null +++ b/source/game/TakeDamageInfo.h @@ -0,0 +1,34 @@ +#ifndef __TAKEDAMAGEINFO_H +#define __TAKEDAMAGEINFO_H + +#include <anim/ModelFile.h> + +class CBaseEntity; + +enum DAMAGE_TYPE +{ + DAMAGE_GENERIC = 0, + DAMAGE_FIRE, + // ... add more +}; + +class CTakeDamageInfo +{ +public: + CTakeDamageInfo(CBaseEntity *pAttacker, float fDamage, DAMAGE_TYPE damageType = DAMAGE_GENERIC): + m_bodyPart(HBP_DEFAULT), + m_pInflictor(NULL), + m_pAttacker(pAttacker), + m_fDamage(fDamage), + m_damageType(damageType) + { + } + + CBaseEntity *m_pInflictor; + CBaseEntity *m_pAttacker; + HITBOX_BODYPART m_bodyPart; + float m_fDamage; + DAMAGE_TYPE m_damageType; +}; + +#endif diff --git a/source/game/Tracer.cpp b/source/game/Tracer.cpp new file mode 100644 index 000000000..f78c23817 --- /dev/null +++ b/source/game/Tracer.cpp @@ -0,0 +1,129 @@ +#include "Tracer.h" +#include <gcore/sxgcore.h> + +CTracer::CTracer(int iTracePoolSize): + m_isTracing(false), + m_iCurTrace(0), + m_iPoolSize(iTracePoolSize), + m_iLineCount(0) +{ + m_vpPoints = new Array<Point>[iTracePoolSize]; +} + +CTracer::~CTracer() +{ + mem_delete_a(m_vpPoints); +} + +//! �������� ����� ����� �� ����� vPoint � ������ fFracColor (0-1) +void CTracer::begin(const float3 &vPoint, float fFracColor) +{ + if(m_isTracing) + { + end(); + } + m_isTracing = true; + + if(m_iLineCount < m_iCurTrace + 1) + { + m_iLineCount = m_iCurTrace + 1; + } + + m_vpPoints[m_iCurTrace].clearFast(); + + putPoint(vPoint, fFracColor); +} + +//! ����������� �������� ����� +void CTracer::end() +{ + if(m_isTracing) + { + m_isTracing = false; + + ++m_iCurTrace; + m_iCurTrace %= m_iPoolSize; + } +} + +//! ������� ��� ������� +void CTracer::clear() +{ + end(); + m_iCurTrace = 0; + m_iLineCount = 0; + + for(int i = 0; i < m_iPoolSize; ++i) + { + m_vpPoints[i].clearFast(); + } +} + +//! �������� ����� �� ��������� ����� +void CTracer::lineTo(const float3 &vPoint, float fFracColor) +{ + putPoint(vPoint, fFracColor); +} + +void CTracer::render() +{ + if(!m_iLineCount) + { + return; + } + + + SGCore_ShaderUnBind(); + + SMMATRIX mView, mProj; + Core_RMatrixGet(G_RI_MATRIX_VIEW, &mView); + Core_RMatrixGet(G_RI_MATRIX_PROJECTION, &mProj); + + SGCore_GetDXDevice()->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&SMMatrixIdentity()); + SGCore_GetDXDevice()->SetTransform(D3DTS_VIEW, (D3DMATRIX*)&mView); + SGCore_GetDXDevice()->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&mProj); + + SGCore_GetDXDevice()->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + SGCore_GetDXDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + SGCore_GetDXDevice()->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + + SGCore_GetDXDevice()->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE); + + SGCore_GetDXDevice()->SetTexture(0, 0); + + // render m_iLineCount traces + for(int i = 0; i < m_iLineCount; ++i) + { + SGCore_GetDXDevice()->DrawPrimitiveUP(D3DPT_LINESTRIP, m_vpPoints[i].size() - 1, &(m_vpPoints[i][0]), sizeof(Point)); + } +} + +void CTracer::putPoint(const float3 &vPoint, float fFracColor) +{ + m_vpPoints[m_iCurTrace].push_back({vPoint, getColor(fFracColor)}); +} + +unsigned int CTracer::getColor(float fFrac) +{ + bool isSecond = fFrac > 0.5f; + unsigned int iStartColor = isSecond ? 0xFFFFFF00 : 0xFFFF0000; + unsigned int iEndColor = isSecond ? 0xFF00FF00 : 0xFFFFFF00; + + unsigned int iResult = 0; + + if(isSecond) + { + fFrac -= 0.5f; + } + fFrac *= 2.0f; + + iResult = (int)lerpf((float)((iStartColor >> 24) & 0xFF), (float)((iEndColor >> 24) & 0xFF), fFrac); + iResult <<= 8; + iResult |= (int)lerpf((float)((iStartColor >> 16) & 0xFF), (float)((iEndColor >> 16) & 0xFF), fFrac); + iResult <<= 8; + iResult |= (int)lerpf((float)((iStartColor >> 8) & 0xFF), (float)((iEndColor >> 8) & 0xFF), fFrac); + iResult <<= 8; + iResult |= (int)lerpf((float)(iStartColor & 0xFF), (float)(iEndColor & 0xFF), fFrac); + + return(iResult); +} diff --git a/source/game/Tracer.h b/source/game/Tracer.h new file mode 100644 index 000000000..f9e155671 --- /dev/null +++ b/source/game/Tracer.h @@ -0,0 +1,46 @@ +#ifndef _TRACER_H_ +#define _TRACER_H_ + +#include <common/sxmath.h> +#include <common/Array.h> + +//! �������� ������ � ������������, ��� ������ +class CTracer +{ +public: + CTracer(int iTracePoolSize = 10); + ~CTracer(); + + //! �������� ����� ����� �� ����� vPoint � ������ fFracColor (0-1) + void begin(const float3 &vPoint, float fFracColor = 0.0f); + + //! ����������� �������� ����� + void end(); + + //! ������� ��� ������� + void clear(); + + //! �������� ����� �� ��������� ����� + void lineTo(const float3 &vPoint, float fFracColor=0.0f); + + void render(); + +protected: + bool m_isTracing; + int m_iCurTrace; + int m_iPoolSize; + int m_iLineCount; + + void putPoint(const float3 &vPoint, float fFracColor); + unsigned int getColor(float fFrac); + + struct Point + { + float3_t vPos; + unsigned int color; + }; + + Array<Point> *m_vpPoints; +}; + +#endif diff --git a/source/mtllight/material.cpp b/source/mtllight/material.cpp index 22b28f6da..ed373db66 100644 --- a/source/mtllight/material.cpp +++ b/source/mtllight/material.cpp @@ -146,6 +146,11 @@ Materials::Material::Material() MainTexture - 1; PreShaderVS - 1; PreShaderPS - 1; + + HitChance = 1.0f; + Penetration = 100.0f; + Density = 1000.0f; + } void Materials::Material::Nulling() diff --git a/source/physics/PhyWorld.cpp b/source/physics/PhyWorld.cpp index 96673b970..325de7d19 100644 --- a/source/physics/PhyWorld.cpp +++ b/source/physics/PhyWorld.cpp @@ -17,7 +17,7 @@ PhyWorld::PhyWorld(): m_pGeomStaticCollideMesh(NULL), m_pGeomStaticCollideShape(NULL), m_pGeomStaticRigidBody(NULL), - m_pGeomMtlTypes(0), + m_pGeomMtlIDs(0), m_iGeomFacesCount(0), m_iGeomModelCount(0), m_ppGreenStaticCollideShape(NULL), @@ -36,7 +36,7 @@ PhyWorld::PhyWorld(): Core_0RegisterCVarString("phy_world_gravity", "0 -10 0", "World gravity (x y z)"); m_pDynamicsWorld->setGravity(btVector3(0, -10, 0)); - + m_pDebugDrawer = new DebugDrawer(); m_pDebugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe); //m_pDebugDrawer->setDebugMode(btIDebugDraw::DBG_FastWireframe); @@ -93,6 +93,11 @@ void PhyWorld::AddShape(btRigidBody * pBody) m_pDynamicsWorld->addRigidBody(pBody); } +void PhyWorld::addShape(btRigidBody * pBody, int group, int mask) +{ + m_pDynamicsWorld->addRigidBody(pBody, group, mask); +} + void PhyWorld::RemoveShape(btRigidBody * pBody) { if(pBody) @@ -124,7 +129,7 @@ void PhyWorld::LoadGeom(const char * file) m_iGeomFacesCount += pIndexCount[tc] / 3; } - m_pGeomMtlTypes = new MTLTYPE_PHYSIC[m_iGeomFacesCount]; + m_pGeomMtlIDs = new ID[m_iGeomFacesCount]; m_iGeomModelCount = iModelCount; m_pGeomStaticCollideMesh = new btTriangleMesh(true, false); @@ -151,7 +156,8 @@ void PhyWorld::LoadGeom(const char * file) } for(int i = 0; i < pIndexCount[tc]; i += 3) { - m_pGeomMtlTypes[iFace++] = SML_MtlGetPhysicMaterial(ppMtls[tc][i]); + //m_pGeomMtlTypes[iFace++] = SML_MtlGetPhysicMaterial(ppMtls[tc][i]); + m_pGeomMtlIDs[iFace++] = ppMtls[tc][i]; m_pGeomStaticCollideMesh->addTriangleIndices(ppIndices[tc][i] + VC, ppIndices[tc][i + 1] + VC, ppIndices[tc][i + 2] + VC); } IC += pIndexCount[tc]; @@ -182,14 +188,14 @@ void PhyWorld::LoadGeom(const char * file) - float3_t** green_arr_vertex; - int32_t* green_arr_count_vertex; - uint32_t** green_arr_index; - ID** green_arr_mtl; - int32_t* green_arr_count_index; - CGreenDataVertex** green_arr_transform; - int32_t* green_arr_count_transform; - int32_t green_arr_count_green; + float3_t** green_arr_vertex = 0; + int32_t* green_arr_count_vertex = 0; + uint32_t** green_arr_index = 0; + ID** green_arr_mtl = 0; + int32_t* green_arr_count_index = 0; + CGreenDataVertex** green_arr_transform = 0; + int32_t* green_arr_count_transform = 0; + int32_t green_arr_count_green = 0; SGeom_GreenGetNavMeshAndTransform(&green_arr_vertex, &green_arr_count_vertex, &green_arr_index, &green_arr_mtl, &green_arr_count_index, &green_arr_transform, &green_arr_count_transform, &green_arr_count_green); @@ -414,7 +420,7 @@ void PhyWorld::UnloadGeom() m_iGeomModelCount = 0; m_iGeomFacesCount = 0; - mem_delete_a(m_pGeomMtlTypes); + mem_delete_a(m_pGeomMtlIDs); } bool PhyWorld::ImportGeom(const char * file) @@ -484,8 +490,8 @@ bool PhyWorld::ImportGeom(const char * file) if(pmf.i64Magick == PHY_MAT_FILE_MAGICK) { m_iGeomFacesCount = pmf.uiGeomFaceCount; - m_pGeomMtlTypes = new MTLTYPE_PHYSIC[m_iGeomFacesCount]; - fread(m_pGeomMtlTypes, sizeof(MTLTYPE_PHYSIC), m_iGeomFacesCount, pF); + m_pGeomMtlIDs = new ID[m_iGeomFacesCount]; + fread(m_pGeomMtlIDs, sizeof(ID), m_iGeomFacesCount, pF); } else { @@ -565,7 +571,7 @@ bool PhyWorld::ExportGeom(const char * _file) PhyMatFile pmf; pmf.uiGeomFaceCount = m_iGeomFacesCount; fwrite(&pmf, sizeof(pmf), 1, file); - fwrite(m_pGeomMtlTypes, sizeof(MTLTYPE_PHYSIC), m_iGeomFacesCount, file); + fwrite(m_pGeomMtlIDs, sizeof(ID), m_iGeomFacesCount, file); fclose(file); } return(ret); @@ -573,13 +579,23 @@ bool PhyWorld::ExportGeom(const char * _file) MTLTYPE_PHYSIC PhyWorld::GetMtlType(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo) { - if(pBody == m_pGeomStaticRigidBody && m_iGeomFacesCount > pShapeInfo->m_triangleIndex) + ID idMtl = GetMtlID(pBody, pShapeInfo); + if(ID_VALID(idMtl)) { - return(m_pGeomMtlTypes[pShapeInfo->m_triangleIndex]); + return(SML_MtlGetPhysicMaterial(idMtl)); } return(MTLTYPE_PHYSIC_DEFAULT); } +ID PhyWorld::GetMtlID(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo) +{ + if(pBody == m_pGeomStaticRigidBody && m_iGeomFacesCount > pShapeInfo->m_triangleIndex) + { + return(m_pGeomMtlIDs[pShapeInfo->m_triangleIndex]); + } + return(-1); +} + //############################################################## void PhyWorld::DebugDrawer::drawLine(const btVector3 & from, const btVector3 & to, const btVector3 & color) @@ -646,8 +662,8 @@ void PhyWorld::DebugDrawer::render() SGCore_GetDXDevice()->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&mProj); SGCore_GetDXDevice()->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); - SGCore_GetDXDevice()->SetRenderState(D3DRS_LIGHTING, FALSE); - SGCore_GetDXDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, 0xFF); + //SGCore_GetDXDevice()->SetRenderState(D3DRS_LIGHTING, FALSE); + //SGCore_GetDXDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, 0xFF); SGCore_GetDXDevice()->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE); diff --git a/source/physics/PhyWorld.h b/source/physics/PhyWorld.h index 435608ca7..d35ba69de 100644 --- a/source/physics/PhyWorld.h +++ b/source/physics/PhyWorld.h @@ -47,8 +47,10 @@ public: void sync(); void AddShape(btRigidBody * pBody); + void addShape(btRigidBody * pBody, int group, int mask); void RemoveShape(btRigidBody * pBody); + void LoadGeom(const char * file=NULL); void UnloadGeom(); @@ -58,6 +60,8 @@ public: void render(); MTLTYPE_PHYSIC GetMtlType(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo); + + ID GetMtlID(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo); btDiscreteDynamicsWorld * GetBtWorld() { @@ -104,7 +108,8 @@ protected: btTriangleMesh * m_pGeomStaticCollideMesh; btCollisionShape * m_pGeomStaticCollideShape; btRigidBody * m_pGeomStaticRigidBody; - MTLTYPE_PHYSIC *m_pGeomMtlTypes; + //MTLTYPE_PHYSIC *m_pGeomMtlTypes; + ID *m_pGeomMtlIDs; int m_iGeomFacesCount; int m_iGeomModelCount; diff --git a/source/physics/sxphysics.h b/source/physics/sxphysics.h index 4c2ee3e85..bc6aae970 100644 --- a/source/physics/sxphysics.h +++ b/source/physics/sxphysics.h @@ -35,6 +35,36 @@ See the license in LICENSE #include <BulletCollision/CollisionDispatch/btGhostObject.h> #include <BulletDynamics/Character/btKinematicCharacterController.h> +#define BIT(n) (1 << n) +enum COLLISION_GROUP +{ + CG_NONE = 0, + // BEGIN --- Do not change --- + CG_DEFAULT = BIT(0), + CG_STATIC = BIT(1), + CG_KINEMATIC = BIT(2), + CG_DEBRIS = BIT(3), + CG_TRIGGER = BIT(4), + CG_CHARACTER = BIT(5), + // END --- Do not change --- + + CG_WATER = BIT(6), + CG_HITBOX = BIT(7), + CG_BULLETFIRE = BIT(8), + + CG_ALL = 0xFFFFFFFF +}; + +//! Описатель физических свойств поверхности +struct SurfaceInfo +{ + ID idMtl; //!< ID материала + float fHitChance; //!< Шанс столкновения пули + float fStrength; //!< Прочность + float fDensity; //!< Плотность + int mat_type; //!< Тип материала +}; + /*! Инициализирует библиотеку */ SX_LIB_API void SXPhysics_0Create(); @@ -83,6 +113,7 @@ SX_LIB_API void SXPhysics_DebugRender(); /*! Добавляет объект в симуляцию */ SX_LIB_API void SXPhysics_AddShape(btRigidBody * pBody); +SX_LIB_API void SXPhysics_AddShapeEx(btRigidBody * pBody, int group, int mask); /*! Удаляет объект из симуляции */ @@ -90,6 +121,8 @@ SX_LIB_API void SXPhysics_RemoveShape(btRigidBody * pBody); SX_LIB_API int SXPhysics_GetMtlType(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo); +SX_LIB_API ID SXPhysics_GetMtlID(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo); + SX_LIB_API btDiscreteDynamicsWorld * SXPhysics_GetDynWorld(); #endif diff --git a/source/physics/sxphysics_dll.cpp b/source/physics/sxphysics_dll.cpp index 3ec2b29dc..96b67a644 100644 --- a/source/physics/sxphysics_dll.cpp +++ b/source/physics/sxphysics_dll.cpp @@ -117,6 +117,12 @@ SX_LIB_API void SXPhysics_AddShape(btRigidBody * pBody) g_pWorld->AddShape(pBody); } +SX_LIB_API void SXPhysics_AddShapeEx(btRigidBody * pBody, int group, int mask) +{ + SP_PRECOND(_VOID); + g_pWorld->addShape(pBody, group, mask); +} + SX_LIB_API void SXPhysics_RemoveShape(btRigidBody * pBody) { SP_PRECOND(_VOID); @@ -146,4 +152,11 @@ SX_LIB_API int SXPhysics_GetMtlType(const btCollisionObject *pBody, const btColl SP_PRECOND(MTLTYPE_PHYSIC_DEFAULT); return(g_pWorld->GetMtlType(pBody, pShapeInfo)); -} \ No newline at end of file +} + +SX_LIB_API ID SXPhysics_GetMtlID(const btCollisionObject *pBody, const btCollisionWorld::LocalShapeInfo *pShapeInfo) +{ + SP_PRECOND(-1); + + return(g_pWorld->GetMtlID(pBody, pShapeInfo)); +} diff --git a/source/skyxengine.cpp b/source/skyxengine.cpp index b2e1b62e1..d806ac1c4 100644 --- a/source/skyxengine.cpp +++ b/source/skyxengine.cpp @@ -435,6 +435,7 @@ void SkyXEngine_CreateLoadCVar() Core_0ConsoleExecCmd("exec ../sysconfig.cfg"); Core_0ConsoleExecCmd("exec ../userconfig.cfg"); + Core_0ConsoleUpdate(); Core_0ConsoleUpdate(); Core_0ConsoleExecCmd("exec ../sysconfig.cfg"); @@ -769,6 +770,10 @@ void SkyXEngine_Frame(DWORD timeDelta) SXPhysics_DebugRender(); #endif +#if defined(SX_GAME) || defined(SX_LEVEL_EDITOR) + SXGame_Render(); +#endif + #if defined(SX_LEVEL_EDITOR) SXLevelEditor::LevelEditorUpdate(timeDelta); #endif -- GitLab