void CDestructibleModel::RegisterDestroyedStimulus() { // Register audio and visual stimulus if specified. if( (m_nDestroyAlarmLevel > 0) && (m_fStimRadius > 0.f) ) { LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); // Extract who caused an explosion. HOBJECT hDamager = m_hLastDamager; if( IsExplosion( hDamager ) ) { Explosion* pExplosion = (Explosion*)g_pLTServer->HandleToObject(m_hLastDamager); hDamager = pExplosion->GetFiredFrom(); } // If damager is still not a character (possibly because an explosion was triggered), assume player. // Better solution - set the alignment of the damager on the explosion? if( !IsCharacter( hDamager ) ) { CPlayerObj *pPlayer = g_pCharacterMgr->FindPlayer(); if ( pPlayer ) { hDamager = pPlayer->m_hObject; } } if ( IsCharacter(hDamager) ) { CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(hDamager); if ( pCharacter ) { // Register the disturbance sound. StimulusRecordCreateStruct DisturbanceSoundSCS( kStim_DisturbanceSound, pCharacter->GetAlignment(), vPos, hDamager ); DisturbanceSoundSCS.m_hStimulusTarget = m_hObject; DisturbanceSoundSCS.m_flAlarmScalar = (float)m_nDestroyAlarmLevel; DisturbanceSoundSCS.m_flRadiusScalar = m_fStimRadius; g_pAIStimulusMgr->RegisterStimulus( DisturbanceSoundSCS ); // Register the visible disturbance. StimulusRecordCreateStruct DisturbanceVisibleSCS( kStim_DisturbanceVisible, pCharacter->GetAlignment(), vPos, hDamager ); DisturbanceVisibleSCS.m_hStimulusTarget = m_hObject; DisturbanceVisibleSCS.m_flAlarmScalar = (float)(m_nDestroyAlarmLevel + 1); DisturbanceVisibleSCS.m_flRadiusScalar = m_fStimRadius; m_eStimID = g_pAIStimulusMgr->RegisterStimulus( DisturbanceVisibleSCS ); } } } }
void TextFont::EndChar() { pivotPoint[0] += charWidth[currentChar] * halfScale[0]; // Row finished? if (IsCharacter(nextChar)) pivotPoint[0] += padding[0]; }
void singleclick(Network::Client* client, u32 serial) { passert_always(client != nullptr && client->chr != nullptr); if (IsCharacter(serial)) { Mobile::Character* chr = nullptr; if (serial == client->chr->serial) chr = client->chr; else chr = find_character(serial); if (chr != nullptr && inrange(client->chr, chr) && !client->chr->is_concealed_from_me(chr)) { if (chr->has_title_guild() && (settingsManager.ssopt.core_handled_tags & 0x1)) send_nametext(client, chr, "[" + chr->title_guild() + "]"); send_nametext(client, chr, chr->name()); std::string tags = create_nametags(chr); if (!tags.empty()) send_nametext(client, chr, tags); } } else // single clicked on an item { Items::Item* item = find_legal_singleclick_item(client->chr, serial); if (item) { send_objdesc(client, item); } } }
LTVector CAIWeaponMelee::GetFirePosition(CAI* pAI) { // Force fire position to come from the edge of the target's radius. // This should ensure a successful melee hit. if( pAI && m_bForceHit ) { HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); if( IsCharacter( hTarget ) ) { LTVector vTargetPos; g_pLTServer->GetObjectPos( hTarget, &vTargetPos ); LTVector vDir = vTargetPos - pAI->GetPosition(); vDir.Normalize(); CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget ); LTVector vFirePos = vTargetPos - ( vDir * pChar->GetRadius() ); return vFirePos; } } // Default behavior. return DefaultGetFirePosition(pAI); }
LTBOOL CAISenseSeeEnemyFootprint::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); CTList<CharFootprintInfo*>* plistFootprints = pChar->GetFootprints(); CharFootprintInfo** ppFootprint = plistFootprints->GetItem(TLIT_FIRST); while ( ppFootprint && *ppFootprint ) { CharFootprintInfo* pFootprint = *ppFootprint; if ( m_pAI->IsPositionVisibleFromEye(CAI::DefaultFilterFn, NULL, pFootprint->vPos, (m_fDistanceSqr), LTTRUE) ) { React(); // Record the Timestamp m_fTimestamp = pFootprint->fTimeStamp; return LTTRUE; } ppFootprint = plistFootprints->GetItem(TLIT_NEXT); } return LTFALSE; }
LTBOOL CAISenseHearEnemyDisturbance::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); CharCoinInfo info; pChar->GetLastCoinInfo(info); if ( /*info.fTime > m_fStimulationTime &&*/ g_pLTServer->GetTime() > info.fTime && g_pLTServer->GetTime() < info.fTime + 0.50f ) { LTFLOAT fDistance = VEC_DIST(info.vPosition, m_pAI->GetPosition()); LTFLOAT fCoinNoiseDistance = g_pAIButeMgr->GetSenses()->fCoinNoiseDistance; fCoinNoiseDistance *= info.fVolume; if ( fDistance < (m_fDistance + fCoinNoiseDistance) ) { React(); // Record the Timestamp m_fTimestamp = info.fTime; // Record the stimulus position m_vStimulusPosition = info.vPosition; return LTTRUE; } } return LTFALSE; }
void CDestructibleModel::RegisterDestroyedStimulus() { // Register audio and visual stimulus if specified. if( (m_nDestroyAlarmLevel > 0) && (m_fStimRadius > 0.f) ) { LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); // Extract who caused an explosion. HOBJECT hDamager = m_hLastDamager; if( IsExplosion( hDamager ) ) { Explosion* pExplosion = (Explosion*)g_pLTServer->HandleToObject(m_hLastDamager); hDamager = pExplosion->GetFiredFrom(); } // If damager is still not a character (possibly because an explosion was triggered), assume player. // Better solution - set the alignment of the damager on the explosion? if( !IsCharacter( hDamager ) ) { CPlayerObj *pPlayer = g_pCharacterMgr->FindPlayer(); if ( pPlayer ) { hDamager = pPlayer->m_hObject; } } g_pAIStimulusMgr->RegisterStimulus( kStim_EnemyDisturbanceSound, m_nDestroyAlarmLevel, hDamager, m_hObject, vPos, m_fStimRadius ); m_eStimID = g_pAIStimulusMgr->RegisterStimulus( kStim_EnemyDisturbanceVisible, m_nDestroyAlarmLevel + 1, hDamager, m_hObject, vPos, m_fStimRadius ); } }
LTBOOL CProjectile::TestInsideObject(HOBJECT hTestObj, AmmoType eAmmoType) { if (!hTestObj) return LTFALSE; // TO DO??? // NOTE: This code may need to be updated to use test the dims // of the CharacterHitBox instead of the dims of the object... // TO DO??? // See if we are inside the test object... LTVector vTestPos, vTestDims; g_pLTServer->GetObjectPos(hTestObj, &vTestPos); g_pLTServer->GetObjectDims(hTestObj, &vTestDims); if (m_vFirePos.x < vTestPos.x - vTestDims.x || m_vFirePos.x > vTestPos.x + vTestDims.x || m_vFirePos.y < vTestPos.y - vTestDims.y || m_vFirePos.y > vTestPos.y + vTestDims.y || m_vFirePos.z < vTestPos.z - vTestDims.z || m_vFirePos.z > vTestPos.z + vTestDims.z) { return LTFALSE; } // We're inside the object, so we automatically hit the object... if (eAmmoType == PROJECTILE) { Detonate(hTestObj); } else { if (eAmmoType == VECTOR) { if (IsCharacter(hTestObj)) { CCharacter *pChar = (CCharacter*) g_pLTServer->HandleToObject(hTestObj); if (!pChar) return LTFALSE; ModelNode eModelNode = g_pModelButeMgr->GetSkeletonDefaultHitNode(pChar->GetModelSkeleton()); pChar->SetModelNodeLastHit(eModelNode); m_fInstDamage *= pChar->ComputeDamageModifier(eModelNode); } ImpactDamageObject(m_hFiredFrom, hTestObj); } LTVector vNormal(0, 1, 0); AddImpact(hTestObj, m_vFlashPos, vTestPos, vNormal, GetSurfaceType(hTestObj)); } RemoveObject(); return LTTRUE; }
bool IsDeadCharacter( HOBJECT hObject ) { if( !hObject ) return true; if( !IsCharacter( hObject ) ) return false; CCharacter *pCharacter = (CCharacter*)g_pLTServer->HandleToObject( hObject ); return ( pCharacter->GetDestructible()->IsDead() ); }
void cbStyledTextCtrl::DoBraceCompletion(const wxChar& ch) { const int pos = GetCurrentPos(); const int style = GetStyleAt(pos); if (IsComment(style) || IsComment(GetStyleAt(pos - 2))) return; // do nothing if (ch == wxT('\'') || ch == wxT('"')) { if (GetCharAt(pos) == ch) { DeleteBack(); CharRight(); } else if (!IsString(GetStyleAt(pos - 2)) && !IsCharacter(GetStyleAt(pos - 2))) InsertText(pos, ch); return; // done } if (IsString(style) || IsCharacter(style)) return; // do nothing const wxString opBraces(wxT("([{")); const int opBraceIdx = opBraces.Find(ch); const wxString clBraces(wxT(")]}")); const int clBraceIdx = clBraces.Find(ch); if ( (opBraceIdx != wxNOT_FOUND) || (clBraceIdx != wxNOT_FOUND) ) { if ( GetCharAt(pos) == ch ) { DeleteBack(); CharRight(); } else if (opBraceIdx != wxNOT_FOUND) { int nextPos = pos; while ( wxIsspace(GetCharAt(nextPos)) && (nextPos < GetLength()) ) ++nextPos; if ( ((wxChar)GetCharAt(nextPos) != clBraces[opBraceIdx]) || (BraceMatch(nextPos) != wxNOT_FOUND) ) { InsertText(pos, clBraces[opBraceIdx]); } } } }
bool cbStyledTextCtrl::AllowTabSmartJump() { const int pos = GetCurrentPos(); if (pos == wxSCI_INVALID_POSITION) return false; const int style = GetStyleAt(pos); if (IsString(style) || IsCharacter(style) || IsComment(style) || IsPreprocessor(style)) return !m_tabSmartJump; return true; }
void CCoin::RotateToRest() { if ( !m_bRotatedToRest ) { char szSpawn[1024]; sprintf(szSpawn, "WeaponItem Gravity 0;AmmoAmount 1;WeaponType Coin;AmmoType Coin"); LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); vPos.y += 2.0f; // This offsets us from the floor a bit so we don't pop through when WeaponItem sets its dims. LTRotation rRot; rRot.Init(); BaseClass* pObj = SpawnObject(szSpawn, vPos, rRot); if ( pObj && pObj->m_hObject ) { g_pLTServer->SetAcceleration(pObj->m_hObject, <Vector(0,0,0)); g_pLTServer->SetVelocity(pObj->m_hObject, <Vector(0,0,0)); } g_pLTServer->SetObjectFlags(m_hObject, g_pLTServer->GetObjectFlags(m_hObject)&~FLAG_VISIBLE); } CGrenade::RotateToRest(); if ( IsCharacter(m_hFiredFrom) ) { LTVector vPosition; g_pLTServer->GetObjectPos(m_hObject, &vPosition); CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(m_hFiredFrom); CharCoinInfo cinfo; cinfo.fTime = g_pLTServer->GetTime(); cinfo.eSurfaceType = m_eLastHitSurface; cinfo.vPosition = vPosition; SURFACE* pSurf = g_pSurfaceMgr->GetSurface(m_eLastHitSurface); _ASSERT(pSurf); if (pSurf) { cinfo.fVolume = pSurf->fMovementNoiseModifier; } else { cinfo.fVolume = 1.0f; } pCharacter->SetLastCoinInfo(&cinfo); } }
void Ladder::UpdatePhysics(ContainerPhysics* pCPStruct) { ILTServer* pServerDE = GetServerDE(); if (!pServerDE) return; if (IsCharacter(pCPStruct->m_hObject)) { CCharacter* pCharacter = (CCharacter*)pServerDE->HandleToObject(pCPStruct->m_hObject); if (pCharacter) { pCharacter->UpdateOnLadder(this, pCPStruct); } } }
void CAIGoalAbstractSearch::SetStateSearch() { // Reset default senses, except for SeeAllyDisturbance. m_pAI->SetCurSenseFlags( 0xffffffff & ~kSense_SeeAllyDisturbance ); // Cannot search without a weapon. CAIHuman* pAIHuman = (CAIHuman*)m_pAI; if( !pAIHuman->GetCurrentWeapon() ) { m_pGoalMgr->LockGoal(this); m_pAI->SetState( kState_HumanDraw ); return; } // Start searching. m_pAI->SetState( kState_HumanSearch ); if( IsCharacter( m_hStimulusSource ) ) { m_pAI->Target(m_hStimulusSource); } m_pGoalMgr->LockGoal(this); CAIHumanStateSearch* pSearchState = (CAIHumanStateSearch*)m_pAI->GetState(); if( pSearchState ) { pSearchState->SetPause(LTTRUE); pSearchState->SetEngage(m_bEngageSearch); pSearchState->SetFace(m_bFaceSearch); // If any optional search regions have been specified, search them. // Otherwise, search the AIs current region. if( !m_lstRegions.empty() ) { AIRegion* pRegion = (AIRegion*)g_pLTServer->HandleToObject( m_lstRegions.front() ); if( pRegion ) { AITRACE( AIShowGoals, ( m_pAI->m_hObject, "Searching region %s", pRegion->GetName() ) ); } pSearchState->SetDestRegion( m_lstRegions.front() ); m_lstRegions.erase( m_lstRegions.begin() ); } } }
ENUM_NMPolyID CAISensorPassTarget::GetTargetNavMeshPoly() { // Target is not a character. HOBJECT hTarget = m_pAI->GetAIBlackBoard()->GetBBTargetObject(); if( !IsCharacter( hTarget ) ) { return kNMPoly_Invalid; } // Return character's NavMesh poly. CCharacter* pTargetChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget ); return pTargetChar->GetCurrentNavMeshPoly(); }
LTBOOL CAISenseHearAllyPain::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; // Don't react to our own pain if ( hStimulus == GetAI()->GetObject() ) return LTFALSE; // See if we can hear the pain CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); // Time has got to be greater than the pain noise time but not too much greater LTFLOAT fTime = g_pLTServer->GetTime(); if ( (fTime > pChar->GetLastPainTime()) && (fTime < pChar->GetLastPainTime() + 1.0f) ) { // Noise has to be within audible radius LTVector vPainPos; g_pLTServer->GetObjectPos(hStimulus, &vPainPos); LTFLOAT fDistance = VEC_DIST(vPainPos, m_pAI->GetPosition()); LTFLOAT fPainNoiseDistance = g_pAIButeMgr->GetSenses()->fAllyPainNoiseDistance; fPainNoiseDistance *= pChar->GetLastPainVolume(); if ( fDistance < (m_fDistance + fPainNoiseDistance) ) { React(); // Record the Timestamp m_fTimestamp = pChar->GetLastPainTime(); // Record the stimulus position m_vStimulusPosition = vPainPos; return LTTRUE; } } return LTFALSE; }
bool CAIWeaponMelee::GetShootPosition( CAI* pAI, AimContext& Context, LTVector& outvShootPos ) { // Force AI to aim directly at the target. if( pAI && m_bForceHit ) { HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); if( IsCharacter( hTarget ) ) { g_pLTServer->GetObjectPos( hTarget, &outvShootPos ); return true; } } // Default behavior. return super::GetShootPosition( pAI, Context, outvShootPos ); }
Ref * sysIsUpperCase( Ref * pc, class MachineClass * vm ) { if ( vm->count != 1 ) throw Ginger::Mishap( "Wrong number of arguments" ); Ref r = vm->fastPeek(); if ( IsCharacter( r ) ) { vm->fastPeek() = isupper( CharacterToChar( r ) ) ? SYS_TRUE : SYS_FALSE; } else if ( IsString( r ) ) { Ref * str_K = RefToPtr4( r ); char * s = reinterpret_cast< char * >( &str_K[ 1 ] ); vm->fastPeek() = SYS_TRUE; while ( *s != 0 ) { if ( not isupper( *s++ ) ) { vm->fastPeek() = SYS_FALSE; break; } } } else { throw Ginger::Mishap( "Non-character argument" ).culprit( "Argument", refToShowString( r ) ); } return pc; }
LTBOOL CAISenseHearEnemyWeaponFire::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); CharFireInfo info; pChar->GetLastFireInfo(info); // Make sure this is a recent firing of the weapon... if (info.fTime + 1.0 < g_pLTServer->GetTime() || info.nWeaponId == WMGR_INVALID_ID) return LTFALSE; WEAPON* pWeapon = g_pWeaponMgr->GetWeapon(info.nWeaponId); if (!pWeapon) return LTFALSE; // Get the Distance that fire noise carries LTFLOAT fWeaponFireNoiseDistance = (LTFLOAT)pWeapon->nAIFireSoundRadius; if (info.bSilenced) fWeaponFireNoiseDistance *= 0.25f; // Get the distance from the fire LTFLOAT fDistance = VEC_DIST(info.vFiredPos, m_pAI->GetPosition()); // Are we close enough to hear? if ( fDistance < (m_fDistance + fWeaponFireNoiseDistance) ) { React(); // Record the Timestamp m_fTimestamp = info.fTime; return LTTRUE; } return LTFALSE; }
int Format(char* num) { int i = 0; int f=1000000; char c; int result = 0; while ((c=*(num+i))!='\0') { if (IsNum(c)) { result += f*(c - '0'); f /= 10; } if (IsCharacter(c)) { result += f*(maps[c - 'A']); f /= 10; } i++; } return result; }
void CAIWeaponAbstract::GetBlindFirePosition(CAI* pAI, LTVector& outvShootPos, bool bMiss ) { ASSERT(pAI); HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); if( !IsCharacter( hTarget ) ) { return; } CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget ); if( !pChar ) { return; } // Intentionally shoot a little short of the target. float fDist = sqrt( pAI->GetTarget()->GetTargetDistSqr() ); float fRadius = pChar->GetRadius(); float fRand = GetRandom( 0.f, 1.f ); fDist -= ( fRadius * 2.f ) + ( fRand * pAI->GetAccuracyMissPerturb() ); // Aim wherever the weapon is aiming. LTVector vDir = pAI->GetWeaponForward( m_pWeapon ); outvShootPos = pAI->GetPosition() + ( vDir * fDist ); // Force bullets to land in front of the target, on the floor. if( bMiss && m_pAIWeaponRecord->bForceMissToFloor ) { float fFloor = pAI->GetAIBlackBoard()->GetBBTargetPosition().y; fFloor -= pAI->GetAIBlackBoard()->GetBBTargetDims().y; outvShootPos.y = fFloor; } }
LTBOOL CAISenseHearEnemyFootstep::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); CharMoveInfo info; pChar->GetLastMoveInfo(info); if ( info.fTime > m_fStimulationTime && g_pLTServer->GetTime() > info.fTime && g_pLTServer->GetTime() < info.fTime + 0.50f ) { LTVector vMovementPos; g_pLTServer->GetObjectPos(hStimulus, &vMovementPos); LTFLOAT fDistance = VEC_DIST(vMovementPos, m_pAI->GetPosition()); LTFLOAT fMovementNoiseDistance = g_pAIButeMgr->GetSenses()->fEnemyMovementNoiseDistance; fMovementNoiseDistance *= info.fVolume; if ( fDistance < (m_fDistance + fMovementNoiseDistance) ) { IncreaseStimulation(fTimeDelta); // Record the timestamp m_fTimestamp = info.fTime; // Record the stimulus position m_vStimulusPosition = vMovementPos; return LTTRUE; } } return LTFALSE; }
bool CKeyMgr::CanCharacterControlObject( HOBJECT hChar, HOBJECT hObj ) { #ifndef _CLIENTBUILD if( !hChar || !hObj || !IsCharacter( hChar )) return false; // If there are no keys that control this object the Character shouldn't be able to control it. KeyControlMap::iterator iter = m_mapKeyControl.find( hObj ); if( iter == m_mapKeyControl.end() ) return false; CCharacter *pChar = (CCharacter*)g_pLTServer->HandleToObject( hChar ); if( !pChar ) return false; IDList *pCharKeyList = pChar->GetKeyList(); uint8 nDummy; IDList& idList = (*iter).second.m_IDList; // Make sure the character has all the keys that are needed to control the object... for( uint8 i = 0; i < idList.m_IDArray.size(); ++i ) { if( !pCharKeyList->Have( idList.m_IDArray[i], nDummy )) { return false; } } #endif return true; }
void CAIWeaponMelee::Fire(CAI* pAI) { if( !m_pWeapon ) { AIASSERT( 0, pAI->GetHOBJECT(), "CAIWeaponMelee::Fire: No weapon!" ); return; } if( m_eFiringState != kAIFiringState_Firing ) { return; } // Fire! LTVector vTargetPos; bool bHit = GetShootPosition( pAI, m_Context, vTargetPos ); if (DefaultFire(pAI, vTargetPos, m_pAIWeaponRecord->bAIAnimatesReload)) { // Decrement burst count for this shot. m_nBurstShots--; } // Knock the player back, if the hit inflicted damage. if( bHit ) { CPlayerObj* pPlayer = NULL; HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); if( IsPlayer( hTarget ) ) { pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject( hTarget ); } if( pPlayer && ( m_pAIWeaponRecord->fPlayerPusherRadius > 0.f ) && ( m_pAIWeaponRecord->fPlayerPusherForce > 0.f ) && ( pPlayer->GetDestructible() ) && ( pPlayer->GetDestructible()->GetLastDamageTime() == g_pLTServer->GetTime() ) && ( pPlayer->GetDestructible()->GetLastDamager() == pAI->m_hObject ) ) { if( ( pPlayer->GetDestructible()->GetLastArmorAbsorb() > 0.f ) || ( pPlayer->GetDestructible()->GetLastDamage() > 0.f ) ) { pPlayer->PushCharacter( pAI->GetPosition(), m_pAIWeaponRecord->fPlayerPusherRadius, 0.f, 0.3f, m_pAIWeaponRecord->fPlayerPusherForce ); } } // Only play if we've been targeting someone for at least 5 seconds. // This ensures we first play higher priority reaction sounds. if( IsCharacter( hTarget ) ) { CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget ); if( pChar && ( pChar->GetDestructible() ) && ( pChar->GetDestructible()->GetLastDamageTime() == g_pLTServer->GetTime() ) && ( pChar->GetDestructible()->GetLastDamager() == pAI->m_hObject ) && ( pAI->GetAIBlackBoard()->GetBBTargetChangeTime() < g_pLTServer->GetTime() - 5.f ) ) { HOBJECT hAlly = g_pAICoordinator->FindAlly( pAI->m_hObject, hTarget ); if( hAlly ) { g_pAISoundMgr->RequestAISound( hAlly, kAIS_HitSeenMelee, kAISndCat_Event, hTarget, 0.5f ); } } } } }
void CreateClientWeaponFX(CLIENTWEAPONFX & theStruct) { if (!g_pLTServer) return; // make sure the impact FX in valid ASSERT( ( 0 <= theStruct.eImpactType ) || ( IMPACT_TYPE_COUNT > theStruct.eImpactType ) ); // If this is a moveable object, set the flags of fx to ignore // marks and smoke... if (IsMoveable(theStruct.hObj)) { theStruct.wIgnoreFX |= WFX_MARK; // Create a server-side mark if applicable... if (CanMarkObject(theStruct.hObj)) { AMMO const *pAmmo = g_pWeaponMgr->GetAmmo(theStruct.nAmmoId); if (pAmmo) { if (pAmmo->pImpactFX) { if (WFX_MARK & pAmmo->pImpactFX->nFlags) { CreateServerMark((CLIENTWEAPONFX)theStruct); } } // Create an exit mark if applicable... if (pAmmo->pFireFX) { if (WFX_EXITMARK & pAmmo->pFireFX->nFlags) { CreateServerExitMark((const CLIENTWEAPONFX)theStruct); } } } } } // Do impact dings if applicable... if (!(IsMultiplayerGame() && IsCharacter(theStruct.hObj))) { theStruct.wIgnoreFX |= WFX_IMPACTDING; } // [KLS 2/28/02] - If the object hit is a character, re-evaluate the surface type. // We do this here because the process of applying damage to the character may have // changed the character's surface type (e.g., from Armor to Flesh). if (IsCharacter(theStruct.hObj)) { theStruct.nSurfaceType = GetSurfaceType(theStruct.hObj); } // Tell all the clients who can see this fx about the fx... CAutoMessage cMsg; cMsg.Writeuint8(SFX_WEAPON_ID); cMsg.WriteObject(theStruct.hObj); cMsg.WriteObject(theStruct.hFiredFrom); cMsg.Writeuint8(theStruct.nWeaponId); cMsg.Writeuint8(theStruct.nAmmoId); cMsg.Writeuint8(theStruct.nSurfaceType); cMsg.Writeuint16(theStruct.wIgnoreFX); cMsg.Writeuint8(theStruct.nShooterId); cMsg.WriteLTVector(theStruct.vFirePos); cMsg.WriteLTVector(theStruct.vPos); cMsg.WriteLTVector(theStruct.vSurfaceNormal); cMsg.Writeuint8(theStruct.eImpactType); g_pLTServer->SendSFXMessage(cMsg.Read(), theStruct.vPos, 0); }
void doubleclick( Network::Client* client, PKTIN_06* msg ) { u32 serial = cfBEu32( msg->serial ); u32 paperdoll_macro_flag = serial & 0x80000000Lu; serial &= ~0x80000000Lu; // keypress versus doubleclick switch? // the find_character would find this, but most of the time it's your own paperdoll. // this is special-cased for two reasons: // 1) it's commonly done // 2) ghosts can doubleclick ONLY their paperdoll. if ( serial == client->chr->serial ) { if ( !paperdoll_macro_flag ) { ScriptDef sd; sd.quickconfig( "scripts/misc/dblclickself.ecl" ); if ( sd.exists() ) { ref_ptr<Bscript::EScriptProgram> prog; prog = find_script2( sd, false, Plib::systemstate.config.cache_interactive_scripts ); if ( prog.get() != nullptr && client->chr->start_script( prog.get(), false ) ) { return; } } } send_paperdoll( client, client->chr ); return; } if ( client->chr->dblclick_wait() > read_gameclock() ) { private_say_above( client->chr, client->chr, "You must wait to use something again." ); return; } else client->chr->dblclick_wait( read_gameclock() + settingsManager.ssopt.dblclick_wait ); if ( IsCharacter( serial ) ) { if ( client->chr->dead() ) return; Mobile::Character* chr = find_character( serial ); if ( !chr ) return; if ( chr->isa( UOBJ_CLASS::CLASS_NPC ) ) { Mobile::NPC* npc = static_cast<Mobile::NPC*>( chr ); if ( npc->can_accept_event( EVID_DOUBLECLICKED ) ) { npc->send_event( new Module::SourcedEvent( EVID_DOUBLECLICKED, client->chr ) ); return; } } bool script_ran = false; ScriptDef sd; sd.quickconfig( "scripts/misc/dblclickother.ecl" ); if ( sd.exists() ) { ref_ptr<Bscript::EScriptProgram> prog; prog = find_script2( sd, false, Plib::systemstate.config.cache_interactive_scripts ); if ( prog.get() != nullptr ) script_ran = client->chr->start_script( prog.get(), false, new Module::ECharacterRefObjImp( chr ) ); } if ( !script_ran && inrange( client->chr, chr ) ) { // MuadDib Changed from a large if || || || to switch case. 1/4/2007 switch ( chr->graphic ) { case UOBJ_HUMAN_MALE: case UOBJ_HUMAN_FEMALE: case UOBJ_HUMAN_MALE_GHOST: case UOBJ_HUMAN_FEMALE_GHOST: case UOBJ_ELF_MALE: case UOBJ_ELF_FEMALE: case UOBJ_ELF_MALE_GHOST: case UOBJ_ELF_FEMALE_GHOST: case UOBJ_GARGOYLE_MALE: case UOBJ_GARGOYLE_FEMALE: case UOBJ_GARGOYLE_MALE_GHOST: case UOBJ_GARGOYLE_FEMALE_GHOST: case UOBJ_GAMEMASTER: case 0x3de: case 0x3df: case 0x3e2: send_paperdoll( client, chr ); break; } } return; } else // doubleclicked an item { // next, search worn items, items in the backpack, and items in the world. Items::Item* item = find_legal_item( client->chr, serial ); // next, check people's backpacks. (don't recurse down) // (not done yet) if ( item != nullptr ) { const Items::ItemDesc& id = item->itemdesc(); if ( !id.ghosts_can_use && client->chr->dead() ) { private_say_above( client->chr, client->chr, "I am dead and cannot do that." ); return; } if ( !id.can_use_while_frozen && client->chr->frozen() ) { private_say_above( client->chr, client->chr, "I am frozen and cannot do that." ); return; } if ( !id.can_use_while_paralyzed && client->chr->paralyzed() ) { private_say_above( client->chr, client->chr, "I am paralyzed and cannot do that." ); return; } unsigned short dst = pol_distance( client->chr, item ); if ( dst > id.doubleclick_range && !client->chr->can_dblclickany() ) { private_say_above( client->chr, item, "That is too far away." ); return; } UObject* obj = item->toplevel_owner(); obj = obj->self_as_owner(); if ( id.use_requires_los && !client->chr->realm->has_los( *client->chr, *obj ) ) // DAVE // 11/24 { private_say_above( client->chr, item, "I can't see that." ); return; } ScriptDef sd; sd.quickconfig( "scripts/misc/dblclickitem.ecl" ); if ( sd.exists() ) { ref_ptr<Bscript::EScriptProgram> prog; prog = find_script2( sd, false, Plib::systemstate.config.cache_interactive_scripts ); if ( prog.get() != nullptr ) client->chr->start_script( prog.get(), false, new Module::EItemRefObjImp( item ) ); } item->double_click( client ); return; } // allow looking into containers being traded if ( client->chr->is_trading() ) { UContainer* cont = client->chr->trade_container()->find_container( serial ); if ( cont != nullptr ) { cont->builtin_on_use( client ); if ( !cont->locked() ) { if ( client->chr->trading_with->client != nullptr ) cont->builtin_on_use( client->chr->trading_with->client ); } return; } } } }
LTBOOL DoVectorFilterFn(HOBJECT hObj, void *pUserData) { // We're not attacking our self... if (SpecificObjectFilterFn(hObj, pUserData)) { // CharacterHitBox objects are used for vector impacts, don't // impact on the character/body prop object itself.... if (IsCharacter(hObj) || IsBody(hObj) || IsKindOf(hObj, "Intelligence")) { return LTFALSE; } // Check special character hit box cases... if (IsCharacterHitBox(hObj)) { CCharacterHitBox *pCharHitBox = (CCharacterHitBox*) g_pLTServer->HandleToObject(hObj); if (pCharHitBox) { // Make sure we don't hit ourself... HOBJECT hUs = (HOBJECT)pUserData; HOBJECT hTestObj = pCharHitBox->GetModelObject(); if (!hTestObj) return LTFALSE; if (hTestObj == hUs) { return LTFALSE; } // Do special AI hitting AI case... if (IsAI(hUs) && IsAI(hTestObj)) { CAI *pAI = (CAI*) g_pLTServer->HandleToObject(hUs); if (!pAI) return LTFALSE; // We can't hit guys we like, unless they're NEUTRAL CCharacter* pB = (CCharacter*)g_pLTServer->HandleToObject(hTestObj); if (!pB) return LTFALSE; CharacterClass cc = pB->GetCharacterClass(); if (cc != NEUTRAL) { return LIKE != GetAlignement(pAI->GetCharacterClass(), cc); } } // Check for friendly fire if (g_pGameServerShell->GetGameType() == COOPERATIVE_ASSAULT && g_vtNetFriendlyFire.GetFloat() < 1.0f) { // We can't hit guys on our team unless friendly fire is turned on if (IsPlayer(hUs) && IsPlayer(hTestObj)) { CPlayerObj* pUs = (CPlayerObj*) g_pLTServer->HandleToObject(hUs); if (!pUs) return LTFALSE; CPlayerObj* pThem = (CPlayerObj*) g_pLTServer->HandleToObject(hTestObj); if (!pThem) return LTFALSE; if (pUs->GetTeamID() == pThem->GetTeamID()) return LTFALSE; } } } } return LTTRUE; } return LTFALSE; }
void CProjectile::AddImpact(HOBJECT hObj, LTVector vFirePos, LTVector vImpactPos, LTVector vSurfaceNormal, SurfaceType eType) { // Create the client side weapon fx... CLIENTWEAPONFX fxStruct; fxStruct.hFiredFrom = m_hFiredFrom; fxStruct.vSurfaceNormal = vSurfaceNormal; fxStruct.vFirePos = vFirePos; fxStruct.vPos = vImpactPos + (m_vDir * -1.0f); fxStruct.hObj = hObj; fxStruct.nWeaponId = m_pWeaponData->nId; fxStruct.nAmmoId = m_pAmmoData->nId; fxStruct.nSurfaceType = eType; fxStruct.wIgnoreFX = g_wIgnoreFX; // Always use the flash position for the first call to AddImpact... if (m_bNumCallsToAddImpact == 0) { fxStruct.vFirePos = m_vFlashPos; } // If we do multiple calls to AddImpact, make sure we only do some // effects once :) g_wIgnoreFX |= WFX_SHELL | WFX_LIGHT | WFX_MUZZLE; // Allow exit surface fx on the next call to AddImpact... g_wIgnoreFX &= ~WFX_EXITSURFACE; if (IsMoveable(hObj)) { // Well, don't do too many exit marks...The server will add one // if necessary... g_wIgnoreFX |= WFX_EXITMARK; } // If this is a player object, get the client id... if (IsPlayer(m_hFiredFrom)) { CPlayerObj* pPlayer = (CPlayerObj*) g_pLTServer->HandleToObject(m_hFiredFrom); if (pPlayer) { fxStruct.nShooterId = (uint8) g_pLTServer->GetClientID(pPlayer->GetClient()); } } CreateClientWeaponFX(fxStruct); // Do the area and progressive (over time) damage... if ((m_pAmmoData->nAreaDamage > 0.0f && eType != ST_SKY) || m_pAmmoData->fProgDamageLifetime > 0.0f) { AddExplosion(vImpactPos, vSurfaceNormal); } // Update Character fire info... if (m_hFiredFrom && IsCharacter(m_hFiredFrom) && CanSetLastFireInfo()) { CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(m_hFiredFrom); if (pChar) { CharFireInfo info; info.hObject = hObj; info.vFiredPos = m_vFlashPos; // Use initial flash pos info.vImpactPos = vImpactPos; info.nWeaponId = m_pWeaponData->nId; info.nAmmoId = m_pAmmoData->nId; info.fTime = g_pLTServer->GetTime(); info.bSilenced = m_bSilenced; info.eSurface = eType; pChar->SetLastFireInfo(&info); } } m_bNumCallsToAddImpact++; }
void CProjectile::HandleTouch(HOBJECT hObj) { if (m_bObjectRemoved) return; // Don't process any touches until this has been cleared... if (m_bProcessInvImpact) return; // Let it get out of our bounding box... if (hObj == m_hFiredFrom) return; CCharacterHitBox* pHitBox = LTNULL; // If we've hit a character (or body), let its hit box take control... if (IsCharacter(hObj)) { CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hObj); if (pChar) { hObj = pChar->GetHitBox(); } } else if (IsBody(hObj)) { Body* pBody = (Body*)g_pLTServer->HandleToObject(hObj); if (pBody) { hObj = pBody->GetHitBox(); } } if (IsCharacterHitBox(hObj)) { pHitBox = (CCharacterHitBox*)g_pLTServer->HandleToObject(hObj); if (!pHitBox) return; if (pHitBox->GetModelObject() == m_hFiredFrom) return; } // Don't hit our own type of projectiles (for multi-projectile weapons // and projectiles that stick to objects)... if (IsKindOf(hObj, m_hObject)) { CProjectile* pObj = (CProjectile*)g_pLTServer->HandleToObject(hObj); if (pObj) { if (pObj->GetFiredFrom() == m_hFiredFrom) { return; } } } // See if we want to impact on this object... uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(hObj); if (dwUsrFlags & USRFLG_IGNORE_PROJECTILES) return; LTBOOL bIsWorld = IsMainWorld(hObj); // Don't impact on non-solid objects...unless it is a CharacterHitBox // object... uint32 dwFlags = g_pLTServer->GetObjectFlags(hObj); if (!bIsWorld && !(dwFlags & FLAG_SOLID)) { if (pHitBox) { // See if we really impacted on the box... if (pHitBox->DidProjectileImpact(this)) { // This is the object that we really hit... hObj = pHitBox->GetModelObject(); } else { return; } } else if (!(dwFlags & FLAG_RAYHIT)) { // If we have ray hit set to true, projectiles should // impact on us too... return; } } // See if we hit the sky... if (bIsWorld || (OT_WORLDMODEL == g_pLTServer->GetObjectType(hObj))) { CollisionInfo info; g_pLTServer->GetLastCollision(&info); SurfaceType eType = GetSurfaceType(info); if (eType == ST_SKY) { RemoveObject(); return; } else if (eType == ST_INVISIBLE) { // Update 1.002 [KLS] - If multiplayer and we hit an invisible // surface, just treat it like a normal surface... if (!IsMultiplayerGame()) { m_bProcessInvImpact = LTTRUE; g_pLTServer->GetObjectPos(m_hObject, &m_vInvisNewPos); g_pLTServer->GetVelocity(m_hObject, &m_vInvisVel); m_vInvisNewPos += (m_vInvisVel * g_pLTServer->GetFrameTime()); // Make sure this new position is inside the world...else // just blow up... if (LT_INSIDE == g_pLTServer->Common()->GetPointStatus(&m_vInvisNewPos)) { return; } } } } HandleImpact(hObj); }
void CProjectile::ImpactDamageObject(HOBJECT hDamager, HOBJECT hObj) { DamageStruct damage; damage.hDamager = hDamager; damage.vDir = m_vDir; // Do Instant damage... if (m_fInstDamage > 0.0f) { damage.eType = m_eInstDamageType; damage.fDamage = m_fInstDamage; damage.DoDamage(this, hObj); } // Do Progressive damage...(if the progressive damage is supposed to // happen over time, it will be done in the explosion object).... if (m_fProgDamage > 0.0f && m_pAmmoData->fProgDamageLifetime <= 0.0f) { damage.eType = m_eProgDamageType; damage.fDamage = m_fProgDamage; damage.fDuration = m_pAmmoData->fProgDamageDuration; damage.DoDamage(this, hObj); } // Update player summary info... CPlayerObj* pPlayer; if (IsPlayer(hDamager) && IsCharacter(hObj) && IsAccuracyType(m_eInstDamageType)) { CCharacter* pChar = (CCharacter*) g_pLTServer->HandleToObject(hObj); pPlayer = (CPlayerObj*) g_pLTServer->HandleToObject(hDamager); if (pPlayer) { ModelNode eModelNode = pChar->GetModelNodeLastHit(); if (eModelNode != eModelNodeInvalid) { HitLocation eLoc = g_pModelButeMgr->GetSkeletonNodeLocation(pChar->GetModelSkeleton(),eModelNode); pPlayer->GetPlayerSummaryMgr()->IncNumHits(eLoc); } else { pPlayer->GetPlayerSummaryMgr()->IncNumHits(HL_UNKNOWN); } } } if (IsPlayer(hObj)) { pPlayer = (CPlayerObj*) g_pLTServer->HandleToObject(hObj); if (pPlayer) { pPlayer->GetPlayerSummaryMgr()->IncNumTimesHit(); } } }