MotionID death_anims::motion ( CEntityAlive& ea, const SHit& H, float &angle ) const { angle = 0; if( anims.empty( ) ) { #ifdef DEBUG if( death_anim_debug ) Msg(" death anims: obj: %s no death motions loaded ", ea.cName().c_str() ); #endif return rnd_anims.motion(); } MotionID m; xr_vector<type_motion*>::const_iterator i = anims.begin(), e = anims.end(); for( ; e!=i; ++i ) if((*i)->predicate( ea, H, m, angle ) && m.valid() ) return m; #ifdef DEBUG if( death_anim_debug ) Msg(" death anims: obj: %s no conditions evaluated returns random ", ea.cName().c_str() ); #endif angle = 0; return rnd_anims.motion(); }
bool HACK_TERRIBLE_DONOT_COLLIDE_ON_SPAWN( CEntityAlive &ea ) { if( pSettings->line_exist( ea.cNameSect().c_str(), "hack_terrible_donot_collide_on_spawn") && pSettings->r_bool( ea.cNameSect().c_str(), "hack_terrible_donot_collide_on_spawn") ) return true; return false; }
BOOL CAI_Rat::feel_vision_isRelevant(CObject* O) { CEntityAlive* E = smart_cast<CEntityAlive*> (O); if (!E) return FALSE; if ((E->g_Team() == g_Team()) && (E->g_Alive())) return FALSE; return TRUE; }
BOOL CBastArtefact::feel_touch_contact(CObject* O) { CEntityAlive* pEntityAlive = smart_cast<CEntityAlive*>(O); if(pEntityAlive && pEntityAlive->g_Alive()) return TRUE; else return FALSE; }
void CBastArtefact::feel_touch_new(CObject* O) { CEntityAlive* pEntityAlive = smart_cast<CEntityAlive*>(O); if(pEntityAlive && pEntityAlive->g_Alive()) { m_AliveList.push_back(pEntityAlive); } }
void CUIInventoryWnd::Update() { if(m_b_need_reinit) InitInventory (); CEntityAlive *pEntityAlive = smart_cast<CEntityAlive*>(Level().CurrentEntity()); if(pEntityAlive) { float v = pEntityAlive->conditions().GetHealth()*100.0f; UIProgressBarHealth.SetProgressPos (v); v = pEntityAlive->conditions().GetPsyHealth()*100.0f; UIProgressBarPsyHealth.SetProgressPos (v); v = pEntityAlive->conditions().GetRadiation()*100.0f; UIProgressBarRadiation.SetProgressPos (v); #ifdef INV_NEW_SLOTS_SYSTEM if (GameID() == GAME_SINGLE){ CActor* m_pActor = smart_cast<CActor*>(Level().CurrentViewEntity()); v =(m_pActor->conditions().GetSatiety())*100.0f; UIProgressBarSatiety.SetProgressPos (v); } #endif CInventoryOwner* pOurInvOwner = smart_cast<CInventoryOwner*>(pEntityAlive); u32 _money = 0; if (GameID() != GAME_SINGLE){ game_PlayerState* ps = Game().GetPlayerByGameID(pEntityAlive->ID()); if (ps){ UIProgressBarRank.SetProgressPos(ps->experience_D*100); _money = ps->money_for_round; } }else { _money = pOurInvOwner->get_money(); } // update money string64 sMoney; //red_virus sprintf_s (sMoney,"%d %s", _money, *CStringTable().translate("ui_st_money_regional")); UIMoneyWnd.SetText (sMoney); // update outfit parameters CCustomOutfit* outfit = smart_cast<CCustomOutfit*>(pOurInvOwner->inventory().m_slots[OUTFIT_SLOT].m_pIItem); UIOutfitInfo.Update (outfit); } UIStaticTimeString.SetText(*InventoryUtilities::GetGameTimeAsString(InventoryUtilities::etpTimeToMinutes)); CUIWindow::Update (); }
void CCameraLook2::Update(Fvector& point, Fvector&) { if(!m_locked_enemy) {//autoaim if( pInput->iGetAsyncKeyState(cam_dik) ) { const CVisualMemoryManager::VISIBLES& vVisibles = Actor()->memory().visual().objects(); CVisualMemoryManager::VISIBLES::const_iterator v_it = vVisibles.begin(); float _nearest_dst = flt_max; for (; v_it!=vVisibles.end(); ++v_it) { const CObject* _object_ = (*v_it).m_object; if (!Actor()->memory().visual().visible_now(smart_cast<const CGameObject*>(_object_))) continue; CObject* object_ = const_cast<CObject*>(_object_); CEntityAlive* EA = smart_cast<CEntityAlive*>(object_); if(!EA || !EA->g_Alive()) continue; float d = object_->Position().distance_to_xz(Actor()->Position()); if( !m_locked_enemy || d<_nearest_dst) { m_locked_enemy = object_; _nearest_dst = d; } } //. if(m_locked_enemy) Msg("enemy is %s", *m_locked_enemy->cNameSect() ); } }else { if( !pInput->iGetAsyncKeyState(cam_dik) ){ m_locked_enemy = NULL; //. Msg ("enemy is NILL"); } } if(m_locked_enemy) UpdateAutoAim (); Fmatrix mR; mR.setHPB (-yaw,-pitch,-roll); vDirection.set (mR.k); vNormal.set (mR.j); Fmatrix a_xform; a_xform.setXYZ (0, -yaw, 0); a_xform.translate_over (point); Fvector _off = m_cam_offset; a_xform.transform_tiny (_off); vPosition.set (_off); }
void CInventoryOwner::SetRank (CHARACTER_RANK_VALUE rank) { CEntityAlive* EA = smart_cast<CEntityAlive*>(this); VERIFY(EA); CSE_Abstract* e_entity = ai().alife().objects().object(EA->ID(), false); if(!e_entity) return; CSE_ALifeTraderAbstract* trader = smart_cast<CSE_ALifeTraderAbstract*>(e_entity); if(!trader) return; CharacterInfo().m_CurrentRank.set(rank); trader->m_rank = rank; }
void CPda::UpdateActiveContacts () { m_active_contacts.clear_not_free(); xr_vector<CObject*>::iterator it= feel_touch.begin(); for(;it!=feel_touch.end();++it){ CEntityAlive* pEA = smart_cast<CEntityAlive*>(*it); if(!!pEA->g_Alive() && !pEA->cast_base_monster()) { m_active_contacts.push_back(*it); } } }
void CBaseGraviZone::AffectPull(CPhysicsShellHolder* GO,const Fvector& throw_in_dir,float dist) { CEntityAlive* EA = smart_cast<CEntityAlive*>(GO); if(EA && EA->g_Alive()) { AffectPullAlife(EA,throw_in_dir,dist); } else if(GO && GO->PPhysicsShell()) { AffectPullDead(GO,throw_in_dir,dist); } }
BOOL CWeapon::ParentIsActor () { CObject* O = H_Parent(); if (!O) return FALSE; CEntityAlive* EA = smart_cast<CEntityAlive*>(O); if (!EA) return FALSE; return EA->cast_actor()!=0; }
void CInventoryOwner::SetReputation (CHARACTER_REPUTATION_VALUE reputation) { CEntityAlive* EA = smart_cast<CEntityAlive*>(this); VERIFY(EA); CSE_Abstract* e_entity = ai().alife().objects().object(EA->ID(), false); if(!e_entity) return; CSE_ALifeTraderAbstract* trader = smart_cast<CSE_ALifeTraderAbstract*>(e_entity); if(!trader) return; CharacterInfo().m_CurrentReputation.set(reputation); trader->m_reputation = reputation; }
void CInventoryOwner::SetCommunity (CHARACTER_COMMUNITY_INDEX new_community) { CEntityAlive* EA = smart_cast<CEntityAlive*>(this); VERIFY(EA); CSE_Abstract* e_entity = ai().alife().objects().object(EA->ID(), false); if(!e_entity) return; CSE_ALifeTraderAbstract* trader = smart_cast<CSE_ALifeTraderAbstract*>(e_entity); if(!trader) return; CharacterInfo().m_CurrentCommunity.set(new_community); // EA->id_Team = CharacterInfo().m_CurrentCommunity.team(); EA->ChangeTeam(CharacterInfo().m_CurrentCommunity.team(), EA->g_Squad(), EA->g_Group()); trader->m_community_index = new_community; }
bool predicate( CEntityAlive& ea, const SHit& H, MotionID &m, float &angle ) const { m = MotionID(); if( H.initiator() != Level().CurrentControlEntity()) return false; VERIFY( ea.Visual( ) ); IKinematics *K = ea.Visual()->dcast_PKinematics(); VERIFY( K ); if( is_bone_head( *K, H.bone() ) ) { edirection dr = dir( ea, H, angle ); m = motion( dr ); type_motion_diagnostic( " type_motion3: 4. ’едшот (по веро¤тности), кроме 5 (4)", dr, ea, H, m ); return true; } return false; }
void CArtefact::UpdateXForm() { if (Device.dwFrame!=dwXF_Frame) { dwXF_Frame = Device.dwFrame; if (0==H_Parent()) return; // Get access to entity and its visual CEntityAlive* E = smart_cast<CEntityAlive*>(H_Parent()); if(!E) return ; const CInventoryOwner *parent = smart_cast<const CInventoryOwner*>(E); if (parent && parent->use_simplified_visual()) return; VERIFY (E); IKinematics* V = smart_cast<IKinematics*> (E->Visual()); VERIFY (V); if(CAttachableItem::enabled()) return; // Get matrices int boneL = -1, boneR = -1, boneR2 = -1; E->g_WeaponBones (boneL,boneR,boneR2); if (boneR == -1) return; boneL = boneR2; V->CalculateBones (); Fmatrix& mL = V->LL_GetTransform(u16(boneL)); Fmatrix& mR = V->LL_GetTransform(u16(boneR)); // Calculate Fmatrix mRes; Fvector R,D,N; D.sub (mL.c,mR.c); D.normalize_safe(); R.crossproduct (mR.j,D); R.normalize_safe(); N.crossproduct (D,R); N.normalize_safe(); mRes.set (R,N,D,mR.c); mRes.mulA_43 (E->XFORM()); // UpdatePosition (mRes); XFORM().mul (mRes,offset()); } }
bool predicate( CEntityAlive& ea, const SHit& H, MotionID &m, float &angle ) const { if( H.initiator() != Level().CurrentControlEntity()) return false; m = MotionID(); VERIFY( ea.Visual( ) ); IKinematics *K = ea.Visual()->dcast_PKinematics(); VERIFY( K ); if(is_snipper( H.weaponID ) && !is_bone_head( *K, H.bone() )) { edirection dr = dir( ea, H, angle ); m = motion( dr ); type_motion_diagnostic( "type_motion5: 6. —найперка в тело", dr, ea, H, m ); return true; } return false; }
bool predicate( CEntityAlive& ea, const SHit& H, MotionID &m, float &angle ) const { m = MotionID(); if( H.initiator() != Level().CurrentControlEntity()) return false; VERIFY( ea.Visual( ) ); IKinematics *K = ea.Visual()->dcast_PKinematics(); VERIFY( K ); if( !is_bone_head( *K, H.bone() )) return false; //CAI_Stalker* s = ea.cast_stalker (); CCharacterPhysicsSupport* chs = ea.character_physics_support(); if( !chs || chs->Type( ) == CCharacterPhysicsSupport::etBitting ) return false; VERIFY( chs->movement() ); const Fvector stalker_velocity = chs->movement()->GetVelocity(); const float stalker_speed = stalker_velocity.magnitude(); const float min_stalker_speed = 3.65f; if(stalker_speed < min_stalker_speed ) return false; const Fvector stalker_velocity_dir = Fvector().mul( stalker_velocity, 1.f/stalker_speed ); const Fvector dir_to_actor = Fvector().sub( H.initiator()->Position(), ea.Position() ).normalize_safe(); const float front_angle_cos = _cos( deg2rad ( 20.f ) ); if( stalker_velocity_dir.dotproduct(dir_to_actor) < front_angle_cos ) return false; if( type_motion::front != type_motion::dir( ea, H, angle ) ) return false; Fvector p; if( Fvector().sub( H.initiator()->Position(), global_hit_position( p, ea, H ) ).magnitude() > 30.f ) return false; m = motion( front ); type_motion_diagnostic( " type_motion0: 1. = »нерционное движение вперед от попадани¤ в голову ", front, ea, H, m ); return true; }
void CBaseMonster::feel_sound_new(CObject* who, int eType, CSound_UserDataPtr user_data, const Fvector &Position, float power) { if (!g_Alive()) return; // ignore my sounds if (this == who) return; if (user_data) user_data->accept (sound_user_data_visitor()); // ignore unknown sounds if (eType == 0xffffffff) return; // ignore distant sounds Fvector center; Center (center); float dist = center.distance_to(Position); if (dist > db().m_max_hear_dist) return; // ignore sounds if not from enemies and not help sounds CEntityAlive* entity = smart_cast<CEntityAlive*> (who); // ignore sound if enemy drop a weapon on death if (!entity && ((eType & SOUND_TYPE_ITEM_HIDING) == SOUND_TYPE_ITEM_HIDING)) return; if (entity && (!EnemyMan.is_enemy(entity))) { SoundMemory.check_help_sound(eType, entity->ai_location().level_vertex_id()); return; } if ((eType & SOUND_TYPE_WEAPON_SHOOTING) == SOUND_TYPE_WEAPON_SHOOTING) power = 1.f; if (((eType & SOUND_TYPE_WEAPON_BULLET_HIT) == SOUND_TYPE_WEAPON_BULLET_HIT) && (dist < 2.f)) HitMemory.add_hit(who,eSideFront); // execute callback sound_callback (who,eType,Position,power); // register in sound memory if (power >= db().m_fSoundThreshold) { SoundMemory.HearSound(who,eType,Position,power,Device.dwTimeGlobal); } }
////////////////////////////////////////////////////////////////////////// // Services ////////////////////////////////////////////////////////////////////////// void CControlManagerCustom::check_attack_jump() { if (!m_object->EnemyMan.get_enemy()) return; if (m_object->GetScriptControl()) return; if (!m_object->check_start_conditions(ControlCom::eControlJump)) return; if (!m_object->EnemyMan.see_enemy_now())return; CEntityAlive *target = const_cast<CEntityAlive*>(m_object->EnemyMan.get_enemy()); if (!m_jump->can_jump(target)) return; if (m_man->check_start_conditions(ControlCom::eControlJump)) { m_jump->setup_data().flags.set (SControlJumpData::ePrepareSkip, false); m_jump->setup_data().target_object = target; m_jump->setup_data().target_position = target->Position(); jump(m_jump->setup_data()); } }
//нам предлагают поговорить, //проверяем наше отношение //и если не враг начинаем разговор bool CInventoryOwner::OfferTalk(CInventoryOwner* talk_partner) { if(!IsTalkEnabled()) return false; //проверить отношение к собеседнику CEntityAlive* pOurEntityAlive = smart_cast<CEntityAlive*>(this); R_ASSERT(pOurEntityAlive); CEntityAlive* pPartnerEntityAlive = smart_cast<CEntityAlive*>(talk_partner); R_ASSERT(pPartnerEntityAlive); // ALife::ERelationType relation = RELATION_REGISTRY().GetRelationType(this, talk_partner); // if(relation == ALife::eRelationTypeEnemy) return false; if(!pOurEntityAlive->g_Alive() || !pPartnerEntityAlive->g_Alive()) return false; StartTalk(talk_partner); return true; }
void CInventoryOwner::UpdateInventoryOwner(u32 deltaT) { inventory().Update(); if(m_pTrade) m_pTrade->UpdateTrade(); if(IsTalking()) { //если наш собеседник перестал говорить с нами, //то и нам нечего ждать. if(!m_pTalkPartner->IsTalking()) { StopTalk(); } //если мы умерли, то тоже не говорить CEntityAlive* pOurEntityAlive = smart_cast<CEntityAlive*>(this); R_ASSERT(pOurEntityAlive); if(!pOurEntityAlive->g_Alive()) StopTalk(); } }
void CPda::shedule_Update(u32 dt) { inherited::shedule_Update (dt); if(!H_Parent()) return; Position().set (H_Parent()->Position()); if( IsOn() && Level().CurrentEntity() && Level().CurrentEntity()->ID()==H_Parent()->ID() ) { CEntityAlive* EA = smart_cast<CEntityAlive*>(H_Parent()); if(!EA || !EA->g_Alive()) { TurnOff(); return; } feel_touch_update(Position(),m_fRadius); UpdateActiveContacts (); } }
void CUIInventoryWnd::Update() { if(m_b_need_reinit) InitInventory (); CEntityAlive *pEntityAlive = smart_cast<CEntityAlive*>(Level().CurrentEntity()); if(pEntityAlive) { float v = pEntityAlive->conditions().GetHealth()*100.0f; UIProgressBarHealth.SetProgressPos (v); v = pEntityAlive->conditions().GetPsyHealth()*100.0f; UIProgressBarPsyHealth.SetProgressPos (v); v = pEntityAlive->conditions().GetRadiation()*100.0f; UIProgressBarRadiation.SetProgressPos (v); if (GameID() != GAME_SINGLE){ game_PlayerState* ps = Game().GetPlayerByGameID(pEntityAlive->ID()); if (ps) UIProgressBarRank.SetProgressPos(ps->experience_D*100); } // update money CInventoryOwner* pOurInvOwner = smart_cast<CInventoryOwner*>(pEntityAlive); string64 sMoney; sprintf (sMoney,"%d RU", pOurInvOwner->get_money()); UIMoneyWnd.SetText (sMoney); // update outfit parameters CCustomOutfit* outfit = smart_cast<CCustomOutfit*>(pOurInvOwner->inventory().m_slots[OUTFIT_SLOT].m_pIItem); UIOutfitInfo.Update (outfit); } //. UITimeWnd.Update (); UIStaticTimeString.SetText(*InventoryUtilities::GetGameTimeAsString(InventoryUtilities::etpTimeToMinutes)); CUIWindow::Update (); }
type_motion::edirection type_motion::dir( CEntityAlive& ea, const SHit& H, float& angle ) { Fvector dir = H.direction(); dir.y = 0; float m = dir.magnitude(); if( fis_zero( m ) ) { edirection dr; dr = (edirection) ::Random.randI( 0, (s32) not_definite ); VERIFY( dr < not_definite ); return dr; } dir.mul( 1.f / m ); Fvector z_dir = { ea.XFORM().k.x, 0.f, ea.XFORM().k.z }; Fvector x_dir = { ea.XFORM().i.x, 0.f, ea.XFORM().i.z }; z_dir.normalize_safe();x_dir.normalize_safe(); float front_factor = dir.dotproduct( z_dir ); float sidefactor = dir.dotproduct( x_dir ); if( _abs( front_factor ) > M_SQRT1_2 ) { float sign = front_factor < 0.f ? -1.f : 1.f; angle = atan2( -sign * sidefactor, sign * front_factor ); return sign < 0.f ? front : back; } else { float sign = sidefactor > 0.f ? 1.f : -1.f; angle = atan2( sign * front_factor, sign * sidefactor ); return sign > 0.f ? left : right; } }
BOOL CBaseMonster::feel_vision_isRelevant(CObject* O) { if (!g_Alive()) return FALSE; if (0==smart_cast<CEntity*>(O)) return FALSE; if ((O->spatial.type & STYPE_VISIBLEFORAI) != STYPE_VISIBLEFORAI) return FALSE; // если спит, то ничего не видит if (m_bSleep) return FALSE; // если не враг - не видит CEntityAlive* entity = smart_cast<CEntityAlive*> (O); if (entity && entity->g_Alive()) { if (!EnemyMan.is_enemy(entity)) { // если видит друга - проверить наличие у него врагов CBaseMonster *monster = smart_cast<CBaseMonster *>(entity); if (monster && !m_skip_transfer_enemy) EnemyMan.transfer_enemy(monster); return FALSE; } } return TRUE; }
void CCustomZone::feel_touch_new (CObject* O) { // if(smart_cast<CActor*>(O) && O == Level().CurrentEntity()) // m_pLocalActor = smart_cast<CActor*>(O); CGameObject* pGameObject = smart_cast<CGameObject*>(O); CEntityAlive* pEntityAlive = smart_cast<CEntityAlive*>(pGameObject); CArtefact* pArtefact = smart_cast<CArtefact*>(pGameObject); SZoneObjectInfo object_info ; object_info.object = pGameObject; if(pEntityAlive && pEntityAlive->g_Alive()) object_info.nonalive_object = false; else object_info.nonalive_object = true; if(pGameObject->Radius()<SMALL_OBJECT_RADIUS) object_info.small_object = true; else object_info.small_object = false; if((object_info.small_object && m_zone_flags.test(eIgnoreSmall)) || (object_info.nonalive_object && m_zone_flags.test(eIgnoreNonAlive)) || (pArtefact && m_zone_flags.test(eIgnoreArtefact))) object_info.zone_ignore = true; else object_info.zone_ignore = false; enter_Zone(object_info); m_ObjectInfoMap.push_back(object_info); if (IsEnabled()) { PlayEntranceParticles(pGameObject); PlayObjectIdleParticles(pGameObject); } };
void type_motion_diagnostic( LPCSTR message, type_motion::edirection dr, const CEntityAlive& ea, const SHit& H, const MotionID &m ) { #ifdef DEBUG if(! death_anim_debug ) return; IKinematicsAnimated *KA = smart_cast<IKinematicsAnimated*>( ea.Visual() ); VERIFY( KA ); IKinematics *K = smart_cast<IKinematics*>( ea.Visual() ); LPCSTR bone_name = "not_definite"; if( H.bone() != BI_NONE ) { CBoneData& bd = K->LL_GetData( H.bone() ); bone_name = bd.name.c_str(); } LPCSTR motion_name = "not_set"; if( m.valid() ) motion_name = KA->LL_MotionDefName_dbg( m ).first; Msg( "death anims: %s, dir: %s, motion: %s, obj: %s, model: %s, bone: %s " ,message ,motion_dirs[ dr ].name, motion_name, ea.cName().c_str(), ea.cNameVisual().c_str(), bone_name ); #endif }
void CInventoryItem::UpdateXForm () { if (0==object().H_Parent()) return; // Get access to entity and its visual CEntityAlive* E = smart_cast<CEntityAlive*>(object().H_Parent()); if (!E) return; if (E->cast_base_monster()) return; const CInventoryOwner *parent = smart_cast<const CInventoryOwner*>(E); if (parent && parent->use_simplified_visual()) return; if (parent->attached(this)) return; R_ASSERT (E); IKinematics* V = smart_cast<IKinematics*> (E->Visual()); VERIFY (V); // Get matrices int boneL = -1, boneR = -1, boneR2 = -1; E->g_WeaponBones(boneL,boneR,boneR2); if (boneR == -1) return; // if ((HandDependence() == hd1Hand) || (STATE == eReload) || (!E->g_Alive())) // boneL = boneR2; #pragma todo("TO ALL: serious performance problem") V->CalculateBones (); Fmatrix& mL = V->LL_GetTransform(u16(boneL)); Fmatrix& mR = V->LL_GetTransform(u16(boneR)); // Calculate Fmatrix mRes; Fvector R,D,N; D.sub (mL.c,mR.c); D.normalize_safe(); if(fis_zero(D.magnitude())) { mRes.set(E->XFORM()); mRes.c.set(mR.c); } else { D.normalize(); R.crossproduct (mR.j,D); N.crossproduct (D,R); N.normalize(); mRes.set (R,N,D,mR.c); mRes.mulA_43 (E->XFORM()); } // UpdatePosition (mRes); object().Position().set(mRes.c); }
bool CBaseMonster::bfAssignMonsterAction(CScriptEntityAction *tpEntityAction) { if (!inherited::bfAssignMonsterAction(tpEntityAction)) return false; CScriptMonsterAction &l_tAction = tpEntityAction->m_tMonsterAction; if (l_tAction.completed()) return false; CEntityAlive *pE = smart_cast<CEntityAlive *>(l_tAction.m_tObject); switch(l_tAction.m_tAction) { case eGA_Rest: StateMan->force_script_state(eStateRest); break; case eGA_Eat: if (pE && !pE->getDestroy() && !pE->g_Alive()){ CorpseMan.force_corpse(pE); StateMan->force_script_state(eStateEat); } else StateMan->force_script_state(eStateRest); break; case eGA_Attack: if (pE && !pE->getDestroy() && pE->g_Alive()){ EnemyMan.force_enemy(pE); StateMan->force_script_state(eStateAttack); } else StateMan->force_script_state(eStateRest); break; case eGA_Panic: if (pE && !pE->getDestroy() && pE->g_Alive()){ EnemyMan.force_enemy (pE); StateMan->force_script_state (eStatePanic); } else StateMan->force_script_state (eStateRest); break; } m_script_state_must_execute = true; return (!l_tAction.m_bCompleted); }
void CWeapon::UpdateXForm () { if (Device.dwFrame == dwXF_Frame) return; dwXF_Frame = Device.dwFrame; if (!H_Parent()) return; // Get access to entity and its visual CEntityAlive* E = smart_cast<CEntityAlive*>(H_Parent()); if (!E) { if (!IsGameTypeSingle()) UpdatePosition (H_Parent()->XFORM()); return; } const CInventoryOwner *parent = smart_cast<const CInventoryOwner*>(E); if (parent && parent->use_simplified_visual()) return; if (parent->attached(this)) return; IKinematics* V = smart_cast<IKinematics*> (E->Visual()); VERIFY (V); // Get matrices int boneL = -1, boneR = -1, boneR2 = -1; // this ugly case is possible in case of a CustomMonster, not a Stalker, nor an Actor E->g_WeaponBones (boneL,boneR,boneR2); if (boneR == -1) return; if ((HandDependence() == hd1Hand) || (GetState() == eReload) || (!E->g_Alive())) boneL = boneR2; V->CalculateBones (); Fmatrix& mL = V->LL_GetTransform(u16(boneL)); Fmatrix& mR = V->LL_GetTransform(u16(boneR)); // Calculate Fmatrix mRes; Fvector R,D,N; D.sub (mL.c,mR.c); if(fis_zero(D.magnitude())) { mRes.set (E->XFORM()); mRes.c.set (mR.c); } else { D.normalize (); R.crossproduct (mR.j,D); N.crossproduct (D,R); N.normalize (); mRes.set (R,N,D,mR.c); mRes.mulA_43 (E->XFORM()); } UpdatePosition (mRes); }