void CScriptDebugging::LogString ( const char* szPrePend, const SLuaDebugInfo& luaDebugInfo, const char* szMessage, unsigned int uiMinimumDebugLevel, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue ) { SString strText = ComposeErrorMessage( szPrePend, luaDebugInfo, szMessage ); // Create a different message if type is "INFO" if ( uiMinimumDebugLevel > 2 ) strText = SString ( "%s%s", szPrePend, szMessage ); if ( !m_bTriggeringOnClientDebugMessage ) { m_bTriggeringOnClientDebugMessage = true; // Prepare onClientDebugMessage CLuaArguments Arguments; Arguments.PushString ( szMessage ); Arguments.PushNumber ( uiMinimumDebugLevel ); // Push the file name (if any) if ( !luaDebugInfo.strFile.empty() ) Arguments.PushString ( luaDebugInfo.strFile ); else Arguments.PushNil ( ); // Push the line (if any) if ( luaDebugInfo.iLine != INVALID_LINE_NUMBER ) Arguments.PushNumber ( luaDebugInfo.iLine ); else Arguments.PushNil ( ); // Call onClientDebugMessage g_pClientGame->GetRootEntity ( )->CallEvent ( "onClientDebugMessage", Arguments, false ); m_bTriggeringOnClientDebugMessage = false; } // Log it to the file if enough level if ( m_uiLogFileLevel >= uiMinimumDebugLevel ) { PrintLog ( strText ); } switch ( uiMinimumDebugLevel ) { case 1: ucRed = 255, ucGreen = 0, ucBlue = 0; break; case 2: ucRed = 255, ucGreen = 128, ucBlue = 0; break; case 3: ucRed = 0, ucGreen = 255, ucBlue = 0; break; } #ifdef MTA_DEBUG if ( !g_pCore->IsDebugVisible () ) return; #endif g_pCore->DebugEchoColor ( strText, ucRed, ucGreen, ucBlue ); }
void CScriptDebugging::LogString ( const char* szPrePend, const SLuaDebugInfo& luaDebugInfo, const char* szMessage, unsigned int uiMinimumDebugLevel, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue ) { SString strText = ComposeErrorMessage( szPrePend, luaDebugInfo, szMessage ); // Create a different message if type is "INFO" if ( uiMinimumDebugLevel > 2 ) strText = SString ( "%s%s", szPrePend, szMessage ); if ( !m_bTriggeringOnClientDebugMessage ) { m_bTriggeringOnClientDebugMessage = true; // Prepare onClientDebugMessage CLuaArguments Arguments; Arguments.PushString ( szMessage ); Arguments.PushNumber ( uiMinimumDebugLevel ); // Push the file name (if any) if ( !luaDebugInfo.strFile.empty() ) Arguments.PushString ( luaDebugInfo.strFile ); else Arguments.PushNil ( ); // Push the line (if any) if ( luaDebugInfo.iLine != INVALID_LINE_NUMBER ) Arguments.PushNumber ( luaDebugInfo.iLine ); else Arguments.PushNil ( ); // Call onClientDebugMessage g_pClientGame->GetRootEntity ( )->CallEvent ( "onClientDebugMessage", Arguments, false ); m_bTriggeringOnClientDebugMessage = false; } switch ( uiMinimumDebugLevel ) { case 1: ucRed = 255, ucGreen = 0, ucBlue = 0; break; case 2: ucRed = 255, ucGreen = 128, ucBlue = 0; break; case 3: ucRed = 0, ucGreen = 255, ucBlue = 0; break; } m_DuplicateLineFilter.AddLine( strText, { uiMinimumDebugLevel, ucRed, ucGreen, ucBlue } ); if ( g_pCore->GetCVars ()->GetValue < bool > ( "filter_duplicate_log_lines" ) == false ) m_DuplicateLineFilter.Flush(); UpdateLogOutput(); }
void CScriptDebugging::LogError ( SString strFile, int iLine, SString strMsg ) { SString strText = SString ( "ERROR: %s:%d: %s", strFile.c_str (), iLine, strMsg.c_str () ); if ( !m_bTriggeringOnDebugMessage ) { m_bTriggeringOnDebugMessage = true; // Prepare onDebugMessage CLuaArguments Arguments; Arguments.PushString ( strMsg.c_str ( ) ); Arguments.PushNumber ( 1 ); // Push the file name (if any) if ( strFile.length ( ) > 0 ) Arguments.PushString ( strFile.c_str ( ) ); else Arguments.PushNil ( ); // Push the line (if any) if ( iLine > -1 ) Arguments.PushNumber ( iLine ); else Arguments.PushNil ( ); // Call onDebugMessage g_pGame->GetMapManager ( )->GetRootElement ( )->CallEvent ( "onDebugMessage", Arguments ); m_bTriggeringOnDebugMessage = false; } // Log it to the file if enough level if ( m_uiLogFileLevel >= 1 ) { PrintLog ( strText ); } // Log to console CLogger::LogPrintf( "%s\n", strText.c_str () ); // Tell the players Broadcast ( CDebugEchoPacket ( strText, 1, 255, 255, 255 ), 1 ); }
void CScriptDebugging::LogString ( const char* szPrePend, const SLuaDebugInfo& luaDebugInfo, const char* szMessage, unsigned int uiMinimumDebugLevel, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue ) { SString strText = ComposeErrorMessage( szPrePend, luaDebugInfo, szMessage ); // Create a different message if type is "INFO" if ( uiMinimumDebugLevel > 2 ) strText = SString ( "%s%s", szPrePend, szMessage ); // Check whether onDebugMessage is currently being triggered if ( !m_bTriggeringOnDebugMessage ) { // Make sure the state of onDebugMessage being triggered can be retrieved later m_bTriggeringOnDebugMessage = true; // Prepare onDebugMessage CLuaArguments Arguments; Arguments.PushString ( szMessage ); Arguments.PushNumber ( uiMinimumDebugLevel ); // Push the file name (if any) if ( !luaDebugInfo.strFile.empty() ) Arguments.PushString ( luaDebugInfo.strFile ); else Arguments.PushNil ( ); // Push the line (if any) if ( luaDebugInfo.iLine != INVALID_LINE_NUMBER ) Arguments.PushNumber ( luaDebugInfo.iLine ); else Arguments.PushNil ( ); // Call onDebugMessage g_pGame->GetMapManager ( )->GetRootElement ( )->CallEvent ( "onDebugMessage", Arguments ); // Reset trigger state, so onDebugMessage can be called again at a later moment m_bTriggeringOnDebugMessage = false; } m_DuplicateLineFilter.AddLine( { strText, uiMinimumDebugLevel, ucRed, ucGreen, ucBlue } ); if ( g_pGame->GetConfig()->GetFilterDuplicateLogLinesEnabled() == false ) m_DuplicateLineFilter.Flush(); UpdateLogOutput(); }
void CScriptDebugging::LogError ( SString strFile, int iLine, SString strMsg ) { SString strText = SString ( "ERROR: %s:%d: %s", strFile.c_str (), iLine, strMsg.c_str () ); if ( !m_bTriggeringOnClientDebugMessage ) { m_bTriggeringOnClientDebugMessage = true; // Prepare onDebugMessage CLuaArguments Arguments; Arguments.PushString ( strMsg.c_str ( ) ); Arguments.PushNumber ( 1 ); // Push the file name (if any) if ( strFile.length ( ) > 0 ) Arguments.PushString ( strFile.c_str ( ) ); else Arguments.PushNil ( ); // Push the line (if any) if ( iLine > -1 ) Arguments.PushNumber ( iLine ); else Arguments.PushNil ( ); // Call onDebugMessage g_pClientGame->GetRootEntity ( )->CallEvent ( "onClientDebugMessage", Arguments, false ); m_bTriggeringOnClientDebugMessage = false; } // Log it to the file if enough level if ( m_uiLogFileLevel >= 1 ) { PrintLog ( strText ); } // Log to console g_pCore->DebugEchoColor ( strText, 255, 0, 0 ); }
void CElementDeleter::Delete ( class CElement* pElement, bool bUnlink, bool bUpdatePerPlayerEntities, CResource* pDebugResource, const char* szDebugText ) { if ( pElement ) { if ( !IsBeingDeleted ( pElement ) ) { // Before we do anything, fire the on-destroy event CLuaArguments Arguments; if ( pDebugResource ) Arguments.PushResource( pDebugResource ); else Arguments.PushNil(); Arguments.PushString( szDebugText ); pElement->CallEvent ( "onElementDestroy", Arguments ); // Add it to our list if ( !pElement->IsBeingDeleted () ) { m_List.push_back ( pElement ); } // Flag it as being deleted and unlink it from the tree/managers pElement->SetIsBeingDeleted ( true ); pElement->ClearChildren (); pElement->SetParentObject ( NULL, bUpdatePerPlayerEntities ); if ( bUnlink ) pElement->Unlink (); } else { if ( pElement->GetType ( ) == CElement::PLAYER ) { // Tell the console CLogger::LogPrint ( "URGENT: Report this error on bugs.mtasa.com error code: 6930-1\n" ); } } } }
void CScriptDebugging::LogString ( const char* szPrePend, lua_State * luaVM, const char* szMessage, unsigned int uiMinimumDebugLevel, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue ) { SString strText; lua_Debug debugInfo; // Initialize values for onDebugMessage SString strMsg = szMessage; SString strFile = ""; int iLine = -1; // Get a VM from somewhere if ( !luaVM && !m_LuaMainStack.empty () ) luaVM = m_LuaMainStack.back ()->GetVM (); for ( int level = 1; level < 3; level++ ) { if ( luaVM && lua_getstack ( luaVM, level, &debugInfo ) ) { lua_getinfo ( luaVM, "nlS", &debugInfo ); // Make sure this function isn't defined in a string (eg: from runcode) if ( debugInfo.source[0] == '@' ) { // Get and store the location of the debug message strFile = debugInfo.source + 1; iLine = debugInfo.currentline; // Populate a message to print/send (unless "info" type) if ( uiMinimumDebugLevel < 3 ) strText = SString ( "%s%s:%d: %s", szPrePend, strFile.c_str (), debugInfo.currentline, szMessage ); // if the file isn't empty, stop trying any other levels break; } else { strFile = debugInfo.short_src; if ( uiMinimumDebugLevel < 3 ) strText = SString ( "%s%s %s", szPrePend, szMessage, strFile.c_str () ); if ( strFile != "[string \"?\"]" ) // if the file isn't empty, stop trying any other levels break; } } else { strText = SString ( "%s%s%s", szPrePend, m_strLineAndFile.c_str(), szMessage ); // no point in trying other levels break; } } // Create a different message if type is "INFO" if ( uiMinimumDebugLevel > 2 ) strText = SString ( "%s%s", szPrePend, szMessage ); // Check whether onDebugMessage is currently being triggered if ( !m_bTriggeringOnDebugMessage ) { // Make sure the state of onDebugMessage being triggered can be retrieved later m_bTriggeringOnDebugMessage = true; // Prepare onDebugMessage CLuaArguments Arguments; Arguments.PushString ( strMsg.c_str ( ) ); Arguments.PushNumber ( uiMinimumDebugLevel ); // Push the file name (if any) if ( strFile.length ( ) > 0 ) Arguments.PushString ( strFile.c_str ( ) ); else Arguments.PushNil ( ); // Push the line (if any) if ( iLine > -1 ) Arguments.PushNumber ( iLine ); else Arguments.PushNil ( ); // Call onDebugMessage g_pGame->GetMapManager ( )->GetRootElement ( )->CallEvent ( "onDebugMessage", Arguments ); // Reset trigger state, so onDebugMessage can be called again at a later moment m_bTriggeringOnDebugMessage = false; } // Log it to the file if enough level if ( m_uiLogFileLevel >= uiMinimumDebugLevel ) { PrintLog ( strText ); } // Log to console CLogger::LogPrintf( "%s\n", strText.c_str () ); // Not sure what this is for, seems pretty useless if ( m_uiHtmlLogLevel >= uiMinimumDebugLevel ) { if ( luaVM ) { CLuaMain* pLuaMain = g_pGame->GetLuaManager()->GetVirtualMachine ( luaVM ); if ( pLuaMain ) { CResourceFile * file = pLuaMain->GetResourceFile(); if ( file && file->GetType() == CResourceHTMLItem::RESOURCE_FILE_TYPE_HTML ) { CResourceHTMLItem * html = (CResourceHTMLItem *)file; html->AppendToPageBuffer ( strText ); html->AppendToPageBuffer ( "<br/>" ); } } } } // Tell the players Broadcast ( CDebugEchoPacket ( strText, uiMinimumDebugLevel, ucRed, ucGreen, ucBlue ), uiMinimumDebugLevel ); }
bool CVehiclePuresyncPacket::Read ( NetBitStreamInterface& BitStream ) { // Got a player to read? if ( m_pSourceElement ) { CPlayer * pSourcePlayer = static_cast < CPlayer * > ( m_pSourceElement ); // Player is in a vehicle? CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle (); if ( pVehicle ) { // Read out the time context unsigned char ucTimeContext = 0; if ( !BitStream.Read ( ucTimeContext ) ) return false; // Only read this packet if it matches the current time context that // player is in. if ( !pSourcePlayer->CanUpdateSync ( ucTimeContext ) ) { return false; } // Read out the keysync data CControllerState ControllerState; if ( !ReadFullKeysync ( ControllerState, BitStream ) ) return false; // Read out its position SPositionSync position ( false ); if ( !BitStream.Read ( &position ) ) return false; pSourcePlayer->SetPosition ( position.data.vecPosition ); // Jax: don't allow any outdated packets through unsigned char ucSeat; if ( !BitStream.Read ( ucSeat ) ) return false; if ( ucSeat != pSourcePlayer->GetOccupiedVehicleSeat () ) { // Mis-matching seats can happen when we warp into a different one, // which will screw up the whole packet return false; } // Read out the vehicle matrix only if he's the driver unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat (); if ( uiSeat == 0 ) { // Read out the vehicle rotation in degrees SRotationDegreesSync rotation; if( !BitStream.Read ( &rotation ) ) return false; // Set it pVehicle->SetPosition ( position.data.vecPosition ); pVehicle->SetRotationDegrees ( rotation.data.vecRotation ); // Move speed vector SVelocitySync velocity; if ( !BitStream.Read ( &velocity ) ) return false; pVehicle->SetVelocity ( velocity.data.vecVelocity ); pSourcePlayer->SetVelocity ( velocity.data.vecVelocity ); // Turn speed vector SVelocitySync turnSpeed; if ( !BitStream.Read ( &turnSpeed ) ) return false; pVehicle->SetTurnSpeed ( turnSpeed.data.vecVelocity ); // Health SVehicleHealthSync health; if ( !BitStream.Read ( &health ) ) return false; float fPreviousHealth = pVehicle->GetHealth (); float fHealth = health.data.fValue; // Less than last time? if ( fHealth < fPreviousHealth ) { // Grab the delta health float fDeltaHealth = fPreviousHealth - fHealth; if ( fDeltaHealth > 0.0f ) { // Call the onVehicleDamage event CLuaArguments Arguments; Arguments.PushNumber ( fDeltaHealth ); pVehicle->CallEvent ( "onVehicleDamage", Arguments ); } } pVehicle->SetHealth ( fHealth ); // Trailer chain CVehicle* pTowedByVehicle = pVehicle; CVehicle* pTrailer = NULL; ElementID TrailerID; bool bHasTrailer; if ( !BitStream.ReadBit ( bHasTrailer ) ) return false; while ( bHasTrailer ) { BitStream.ReadCompressed ( TrailerID ); CElement* pElement = CElementIDs::GetElement ( TrailerID ); if ( pElement ) pTrailer = static_cast < CVehicle* > ( pElement ); // Read out the trailer position and rotation SPositionSync trailerPosition ( false ); if ( !BitStream.Read ( &trailerPosition ) ) return false; SRotationDegreesSync trailerRotation; if ( !BitStream.Read ( &trailerRotation ) ) return false; // If we found the trailer if ( pTrailer ) { // Set its position and rotation pTrailer->SetPosition ( trailerPosition.data.vecPosition ); pTrailer->SetRotationDegrees ( trailerRotation.data.vecRotation ); // Is this a new trailer, attached? CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle (); if ( pCurrentTrailer != pTrailer ) { // If theres a trailer already attached if ( pCurrentTrailer ) { pTowedByVehicle->SetTowedVehicle ( NULL ); pCurrentTrailer->SetTowedByVehicle ( NULL ); // Tell everyone to detach them CVehicleTrailerPacket AttachPacket ( pTowedByVehicle, pCurrentTrailer, false ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( AttachPacket ); // Execute the attach trailer script function CLuaArguments Arguments; Arguments.PushElement ( pTowedByVehicle ); pCurrentTrailer->CallEvent ( "onTrailerDetach", Arguments ); } // If something else is towing this trailer CVehicle* pCurrentVehicle = pTrailer->GetTowedByVehicle (); if ( pCurrentVehicle ) { pCurrentVehicle->SetTowedVehicle ( NULL ); pTrailer->SetTowedByVehicle ( NULL ); // Tell everyone to detach them CVehicleTrailerPacket AttachPacket ( pCurrentVehicle, pTrailer, false ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( AttachPacket ); // Execute the attach trailer script function CLuaArguments Arguments; Arguments.PushElement ( pCurrentVehicle ); pTrailer->CallEvent ( "onTrailerDetach", Arguments ); } pTowedByVehicle->SetTowedVehicle ( pTrailer ); pTrailer->SetTowedByVehicle ( pTowedByVehicle ); // Execute the attach trailer script function CLuaArguments Arguments; Arguments.PushElement ( pTowedByVehicle ); bool bContinue = pTrailer->CallEvent ( "onTrailerAttach", Arguments ); // Attach or detach trailers depending on the event outcome CVehicleTrailerPacket TrailerPacket ( pTowedByVehicle, pTrailer, bContinue ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( TrailerPacket ); } } else break; pTowedByVehicle = pTrailer; if ( BitStream.ReadBit ( bHasTrailer ) == false ) return false; } // If there was a trailer before CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle (); if ( pCurrentTrailer ) { pTowedByVehicle->SetTowedVehicle ( NULL ); pCurrentTrailer->SetTowedByVehicle ( NULL ); // Tell everyone else to detach them CVehicleTrailerPacket AttachPacket ( pTowedByVehicle, pCurrentTrailer, false ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( AttachPacket ); // Execute the detach trailer script function CLuaArguments Arguments; Arguments.PushElement ( pTowedByVehicle ); pCurrentTrailer->CallEvent ( "onTrailerDetach", Arguments ); } } // Player health SPlayerHealthSync health; if ( !BitStream.Read ( &health ) ) return false; float fHealth = health.data.fValue; float fOldHealth = pSourcePlayer->GetHealth (); float fHealthLoss = fOldHealth - fHealth; // Less than last packet's frame? if ( fHealth < fOldHealth && fHealthLoss > 0 ) { // Call the onPlayerDamage event CLuaArguments Arguments; Arguments.PushNil (); Arguments.PushNumber ( false ); Arguments.PushNumber ( false ); Arguments.PushNumber ( fHealthLoss ); pSourcePlayer->CallEvent ( "onPlayerDamage", Arguments ); } pSourcePlayer->SetHealth ( fHealth ); // Armor SPlayerArmorSync armor; if ( !BitStream.Read ( &armor ) ) return false; float fArmor = armor.data.fValue; float fOldArmor = pSourcePlayer->GetArmor (); float fArmorLoss = fOldArmor - fArmor; // Less than last packet's frame? if ( fArmor < fOldArmor && fArmorLoss > 0 ) { // Call the onPlayerDamage event CLuaArguments Arguments; Arguments.PushNil (); Arguments.PushNumber ( false ); Arguments.PushNumber ( false ); Arguments.PushNumber ( fArmorLoss ); pSourcePlayer->CallEvent ( "onPlayerDamage", Arguments ); } pSourcePlayer->SetArmor ( fArmor ); // Flags SVehiclePuresyncFlags flags; if ( !BitStream.Read ( &flags ) ) return false; pSourcePlayer->SetWearingGoggles ( flags.data.bIsWearingGoggles ); pSourcePlayer->SetDoingGangDriveby ( flags.data.bIsDoingGangDriveby ); // Weapon sync if ( flags.data.bHasAWeapon ) { SWeaponSlotSync slot; if ( !BitStream.Read ( &slot ) ) return false; pSourcePlayer->SetWeaponSlot ( slot.data.uiSlot ); if ( flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo ( slot.data.uiSlot ) ) { // Read the ammo states SWeaponAmmoSync ammo ( pSourcePlayer->GetWeaponType (), false, true ); if ( !BitStream.Read ( &ammo ) ) return false; pSourcePlayer->SetWeaponAmmoInClip ( ammo.data.usAmmoInClip ); // Read aim data SWeaponAimSync aim ( pSourcePlayer->GetWeaponRange (), true ); if ( !BitStream.Read ( &aim ) ) return false; pSourcePlayer->SetAimDirection ( aim.data.fArm ); pSourcePlayer->SetSniperSourceVector ( aim.data.vecOrigin ); pSourcePlayer->SetTargettingVector ( aim.data.vecTarget ); // Read the driveby direction SDrivebyDirectionSync driveby; if ( !BitStream.Read ( &driveby ) ) return false; pSourcePlayer->SetDriveByDirection ( driveby.data.ucDirection ); } } else pSourcePlayer->SetWeaponSlot ( 0 ); // Vehicle specific data if he's the driver if ( uiSeat == 0 ) { ReadVehicleSpecific ( pVehicle, BitStream ); // Set vehicle specific stuff if he's the driver pVehicle->SetSirenActive ( flags.data.bIsSirenOrAlarmActive ); pVehicle->SetSmokeTrailEnabled ( flags.data.bIsSmokeTrailEnabled ); pVehicle->SetLandingGearDown ( flags.data.bIsLandingGearDown ); pVehicle->SetOnGround ( flags.data.bIsOnGround ); pVehicle->SetInWater ( flags.data.bIsInWater ); pVehicle->SetDerailed ( flags.data.bIsDerailed ); pVehicle->SetHeliSearchLightVisible ( flags.data.bIsHeliSearchLightVisible ); } // Read the vehicle_look_left and vehicle_look_right control states // if it's an aircraft. if ( flags.data.bIsAircraft ) { ControllerState.LeftShoulder2 = BitStream.ReadBit () * 255; ControllerState.RightShoulder2 = BitStream.ReadBit () * 255; } pSourcePlayer->GetPad ()->NewControllerState ( ControllerState ); // Success return true; } } return false; }
// Set ( resource requesting the query, setting name, content ) bool CSettings::Set(const char *szLocalResource, const char *szSetting, const char *szContent) { CXMLNode * pNode; CResource * pResource; CXMLAttributes *pAttributes; char szBuffer[MAX_SETTINGS_LENGTH] = {0}; char szQueryResource[MAX_RESOURCE_LENGTH] = {0}; SettingStatus eStatus; bool bDeleteNode, bExists; SString strOldValue; // Check for empty strings if (strlen(szSetting) < 1) return false; // Get the actual resource name from the specified setting, and get the resource class if (!GetResourceName(szSetting, szQueryResource, MAX_RESOURCE_LENGTH - 1)) { // No name was specified, so use the local resource pResource = m_pResourceManager->GetResource(szLocalResource); } else pResource = m_pResourceManager->GetResource(szQueryResource); // If we have a valid resource if (pResource) { CXMLNode *pSource = pResource->GetSettingsNode(); // Check whether the setting exists in the settings registry pNode = Get(m_pNodeGlobalSettings, NULL, "", szLocalResource, szSetting, bDeleteNode, eStatus); bExists = true; // Default value // Try to get the value for the appropriate setting from the resource's meta XML file if (eStatus == NotFound && pSource) { pNode = Get(pSource, NULL, pResource->GetName().c_str(), szLocalResource, szSetting, bDeleteNode, eStatus); bExists = false; // There's no node in the settings registry, so we create one } // See if we have access if (eStatus != NoAccess) { // See if we have a prefix bool bPrefix = HasPrefix(szSetting[0]); // If no resource name was specified, use the local resource name if (!HasResourceName(szSetting)) { // If we have a prefix, move it from szSetting and put it at the beginning if (bPrefix) snprintf(szBuffer, MAX_SETTINGS_LENGTH - 1, "%c%s.%s", szSetting[0], szLocalResource, szSetting + 1); else snprintf(szBuffer, MAX_SETTINGS_LENGTH - 1, "%s.%s", szLocalResource, szSetting); } else { // If we have a prefix, move it from szSetting and put it at the beginning if (bPrefix) snprintf(szBuffer, MAX_SETTINGS_LENGTH - 1, "%c%s", szSetting[0], szSetting + 1); else strncpy(szBuffer, szSetting, MAX_SETTINGS_LENGTH - 1); } if (!bExists || !pNode) { // No existing settings registry entry, so create a new setting CreateSetting(m_pNodeGlobalSettings, szBuffer, szContent); } else { // Existing settings registry entry // Get the attributes pAttributes = &(pNode->GetAttributes()); // Abort if this value isnt public (but protected or private), and if the local resource // (doing the query) doesn't equal the setting's resource name if (GetAccessType(pAttributes->Find("name")->GetValue()[0]) != CSettings::Public && stricmp(pResource->GetName().c_str(), szLocalResource) != 0) return false; // Get the node's current value strOldValue = pAttributes->Find("value")->GetValue(); // Set the node's value pAttributes->Find("value")->SetValue(szContent); // If a prefix was given, set the node's name (to override any access operators) if (bPrefix) pAttributes->Find("name")->SetValue(szBuffer); } // Trigger onSettingChange CLuaArguments Arguments; Arguments.PushString(szSetting); if (strOldValue.length() > 0) Arguments.PushString(strOldValue.c_str()); else Arguments.PushNil(); Arguments.PushString(szContent); g_pGame->GetMapManager()->GetRootElement()->CallEvent("onSettingChange", Arguments); // Save the XML file if (m_pFile->Write()) return true; CLogger::ErrorPrintf("Error saving '%s'\n", FILENAME_SETTINGS); } } return false; }
bool CPlayerPuresyncPacket::Read ( NetBitStreamInterface& BitStream ) { if ( m_pSourceElement ) { CPlayer * pSourcePlayer = static_cast < CPlayer * > ( m_pSourceElement ); // Read out the time context unsigned char ucTimeContext = 0; if ( !BitStream.Read ( ucTimeContext ) ) return false; // Only read this packet if it matches the current time context that // player is in. if ( !pSourcePlayer->CanUpdateSync ( ucTimeContext ) ) { return false; } // Read out keys CControllerState ControllerState; ReadFullKeysync ( ControllerState, BitStream ); pSourcePlayer->GetPad ()->NewControllerState ( ControllerState ); // Read the flags SPlayerPuresyncFlags flags; if ( !BitStream.Read ( &flags ) ) return false; pSourcePlayer->SetInWater ( flags.data.bIsInWater ); pSourcePlayer->SetOnGround ( flags.data.bIsOnGround ); pSourcePlayer->SetHasJetPack ( flags.data.bHasJetPack ); pSourcePlayer->SetDucked ( flags.data.bIsDucked ); pSourcePlayer->SetWearingGoggles ( flags.data.bWearsGoogles ); pSourcePlayer->SetChoking ( flags.data.bIsChoking ); pSourcePlayer->SetAkimboArmUp ( flags.data.bAkimboTargetUp ); pSourcePlayer->SetOnFire ( flags.data.bIsOnFire ); pSourcePlayer->SetStealthAiming ( flags.data.bStealthAiming ); // Contact element CElement* pContactElement = NULL; if ( flags.data.bHasContact ) { ElementID Temp; if ( !BitStream.ReadCompressed ( Temp ) ) return false; pContactElement = CElementIDs::GetElement ( Temp ); } CElement * pPreviousContactElement = pSourcePlayer->GetContactElement (); pSourcePlayer->SetContactElement ( pContactElement ); if ( pPreviousContactElement != pContactElement ) { // Call our onPlayerContact event CLuaArguments Arguments; if ( pPreviousContactElement ) Arguments.PushElement ( pPreviousContactElement ); else Arguments.PushNil (); if ( pContactElement ) Arguments.PushElement ( pContactElement ); else Arguments.PushNil (); pSourcePlayer->CallEvent ( "onPlayerContact", Arguments ); } // Player position SPositionSync position ( false ); if ( !BitStream.Read ( &position ) ) return false; if ( pContactElement ) { pSourcePlayer->SetContactPosition ( position.data.vecPosition ); // Get the true position CVector vecTempPos = pContactElement->GetPosition (); position.data.vecPosition += vecTempPos; } pSourcePlayer->SetPosition ( position.data.vecPosition ); // Player rotation SPedRotationSync rotation; if ( !BitStream.Read ( &rotation ) ) return false; pSourcePlayer->SetRotation ( rotation.data.fRotation ); // Move speed vector if ( flags.data.bSyncingVelocity ) { SVelocitySync velocity; if ( !BitStream.Read ( &velocity ) ) return false; pSourcePlayer->SetVelocity ( velocity.data.vecVelocity ); } // Health ( stored with damage ) SPlayerHealthSync health; if ( !BitStream.Read ( &health ) ) return false; float fHealth = health.data.fValue; // Armor SPlayerArmorSync armor; if ( !BitStream.Read ( &armor ) ) return false; float fArmor = armor.data.fValue; float fOldArmor = pSourcePlayer->GetArmor (); float fArmorLoss = fOldArmor - fArmor; pSourcePlayer->SetArmor ( fArmor ); // Read out and set the camera rotation float fCameraRotation; if ( !BitStream.Read ( fCameraRotation ) ) return false; pSourcePlayer->SetCameraRotation ( fCameraRotation ); if ( flags.data.bHasAWeapon ) { if ( BitStream.Version () >= 0x0d ) { // Check client has the weapon we think he has unsigned char ucWeaponType; if ( !BitStream.Read ( ucWeaponType ) ) return false; if ( pSourcePlayer->GetWeaponType () != ucWeaponType ) return false; } // Current weapon slot SWeaponSlotSync slot; if ( !BitStream.Read ( &slot ) ) return false; unsigned int uiSlot = slot.data.uiSlot; pSourcePlayer->SetWeaponSlot ( uiSlot ); if ( CWeaponNames::DoesSlotHaveAmmo ( uiSlot ) ) { // Read out the ammo states SWeaponAmmoSync ammo ( pSourcePlayer->GetWeaponType (), true, true ); if ( !BitStream.Read ( &ammo ) ) return false; pSourcePlayer->SetWeaponAmmoInClip ( ammo.data.usAmmoInClip ); pSourcePlayer->SetWeaponTotalAmmo ( ammo.data.usTotalAmmo ); // Read out the aim data SWeaponAimSync sync ( pSourcePlayer->GetWeaponRange (), ( ControllerState.RightShoulder1 || ControllerState.ButtonCircle ) ); if ( !BitStream.Read ( &sync ) ) return false; // Set the arm directions and whether or not arms are up pSourcePlayer->SetAimDirection ( sync.data.fArm ); // Read the aim data only if he's shooting or aiming if ( sync.isFull() ) { pSourcePlayer->SetSniperSourceVector ( sync.data.vecOrigin ); pSourcePlayer->SetTargettingVector ( sync.data.vecTarget ); } } else { pSourcePlayer->SetWeaponAmmoInClip ( 1 ); pSourcePlayer->SetWeaponTotalAmmo ( 1 ); } } else { pSourcePlayer->SetWeaponSlot ( 0 ); pSourcePlayer->SetWeaponAmmoInClip ( 1 ); pSourcePlayer->SetWeaponTotalAmmo ( 1 ); } // Read out damage info if changed if ( BitStream.ReadBit () == true ) { ElementID DamagerID; if ( !BitStream.ReadCompressed ( DamagerID ) ) return false; SWeaponTypeSync weaponType; if ( !BitStream.Read ( &weaponType ) ) return false; SBodypartSync bodyPart; if ( !BitStream.Read ( &bodyPart ) ) return false; pSourcePlayer->SetDamageInfo ( DamagerID, weaponType.data.ucWeaponType, bodyPart.data.uiBodypart ); } // If we know the player's dead, make sure the health we send on is 0 if ( pSourcePlayer->IsDead () ) fHealth = 0.0f; float fOldHealth = pSourcePlayer->GetHealth (); float fHealthLoss = fOldHealth - fHealth; pSourcePlayer->SetHealth ( fHealth ); // Less than last packet's frame? if ( fHealthLoss > 0 || fArmorLoss > 0 ) { float fDamage = 0.0f; if ( fHealthLoss > 0 ) fDamage += fHealthLoss; if ( fArmorLoss > 0 ) fDamage += fArmorLoss; // Call the onPlayerDamage event CLuaArguments Arguments; CElement* pKillerElement = CElementIDs::GetElement ( pSourcePlayer->GetPlayerAttacker () ); if ( pKillerElement ) Arguments.PushElement ( pKillerElement ); else Arguments.PushNil (); Arguments.PushNumber ( pSourcePlayer->GetAttackWeapon () ); Arguments.PushNumber ( pSourcePlayer->GetAttackBodyPart () ); Arguments.PushNumber ( fDamage ); pSourcePlayer->CallEvent ( "onPlayerDamage", Arguments ); } // Success return true; } return false; }
void CRPCFunctions::CursorEvent ( NetBitStreamInterface & bitStream ) { SMouseButtonSync button; unsigned char ucButton; CVector2D vecCursorPosition; unsigned short usX; unsigned short usY; SPositionSync position ( false ); CVector vecPosition; bool bHasCollisionElement; ElementID elementID; if ( bitStream.Read ( &button ) && bitStream.ReadCompressed ( usX ) && bitStream.ReadCompressed ( usY ) && bitStream.Read ( &position ) && bitStream.ReadBit ( bHasCollisionElement ) && ( !bHasCollisionElement || bitStream.ReadCompressed ( elementID ) ) ) { ucButton = button.data.ucButton; vecCursorPosition.fX = static_cast < float > ( usX ); vecCursorPosition.fY = static_cast < float > ( usY ); vecPosition = position.data.vecPosition; if ( !bHasCollisionElement ) elementID = INVALID_ELEMENT_ID; } else return; if ( m_pSourcePlayer->IsJoined () ) { // Get the button and state const char* szButton = NULL; const char* szState = NULL; switch ( ucButton ) { case 0: szButton = "left"; szState = "down"; break; case 1: szButton = "left"; szState = "up"; break; case 2: szButton = "middle"; szState = "down"; break; case 3: szButton = "middle"; szState = "up"; break; case 4: szButton = "right"; szState = "down"; break; case 5: szButton = "right"; szState = "up"; break; } if ( szButton && szState ) { CElement* pElement = CElementIDs::GetElement ( elementID ); if ( pElement ) { // Call the onElementClicked event CLuaArguments Arguments; Arguments.PushString ( szButton ); Arguments.PushString ( szState ); Arguments.PushElement ( m_pSourcePlayer ); Arguments.PushNumber ( vecPosition.fX ); Arguments.PushNumber ( vecPosition.fY ); Arguments.PushNumber ( vecPosition.fZ ); pElement->CallEvent ( "onElementClicked", Arguments ); } // Call the onPlayerClick event CLuaArguments Arguments; Arguments.PushString ( szButton ); Arguments.PushString ( szState ); if ( pElement ) Arguments.PushElement ( pElement ); else Arguments.PushNil (); Arguments.PushNumber ( vecPosition.fX ); Arguments.PushNumber ( vecPosition.fY ); Arguments.PushNumber ( vecPosition.fZ ); Arguments.PushNumber ( vecCursorPosition.fX ); Arguments.PushNumber ( vecCursorPosition.fY ); m_pSourcePlayer->CallEvent ( "onPlayerClick", Arguments ); // TODO: iterate server-side element managers for the click events, eg: colshapes } } }
void CClientWeapon::FireInstantHit ( CVector vecOrigin, CVector vecTarget, bool bServerFire, bool bRemote ) #endif { CVector vecDirection = vecTarget - vecOrigin; vecDirection.Normalize (); CClientEntity * pAttachedTo = GetAttachedTo (); CVector vecOriginalTarget = vecTarget; CEntity * pColEntity = NULL; CColPoint * pColPoint = NULL; SLineOfSightBuildingResult pBuildingResult; CEntitySAInterface * pEntity = NULL; if ( m_Type != WEAPONTYPE_SHOTGUN ) { CVector vecWeaponFirePosition; if ( !IsLocalEntity ( ) && m_pOwner ) { CClientPlayer * pPlayer = m_pOwner; CClientPed * pLocalPlayer = g_pClientGame->GetLocalPlayer(); if ( pLocalPlayer && pPlayer ) { CClientVehicle* pVehicle = pLocalPlayer->GetRealOccupiedVehicle (); // Move both players to where they should be for shot compensation if ( pPlayer && !pPlayer->IsLocalPlayer () ) { if ( !pVehicle || pLocalPlayer->GetOccupiedVehicleSeat() == 0 ) { // Warp back in time to where we were when this player shot (their latency) // We don't account for interpolation here, +250ms seems to work better // ** Changed ajustment to +125ms as the position of this clients player on the firers screen // has been changed. See CClientPed::UpdateTargetPosition() ** CVector vecPosition; unsigned short usLatency = ( pPlayer->GetLatency () + 125 ); g_pClientGame->GetNetAPI()->GetInterpolation ( vecPosition, usLatency ); // Move the entity back if ( pVehicle ) { pVehicle->GetPosition ( vecWeaponFirePosition ); pVehicle->SetPosition ( vecPosition, false, false ); } else { pLocalPlayer->GetPosition ( vecWeaponFirePosition ); pLocalPlayer->SetPosition ( vecPosition, false, false ); } } } } } //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( true ); if ( m_pWeapon->ProcessLineOfSight ( &vecOrigin, &vecTarget, &pColPoint, &pColEntity, m_weaponConfig.flags, &pBuildingResult, m_Type, &pEntity ) ) { vecTarget = pColPoint->GetPosition (); } // Don't continue without a valid colpoint if ( !pColPoint ) return; //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( false ); // return if shoot if target is blocked is false and we aren't pointing at our target if ( ( m_pTarget != NULL && m_pTarget->GetGameEntity ( ) != NULL && m_pTarget->GetGameEntity()->GetInterface ( ) != pEntity ) && m_weaponConfig.bShootIfTargetBlocked == false && bRemote == false ) { if ( pColPoint ) pColPoint->Destroy (); return; } // Execute our weapon fire event CClientEntity * pClientEntity = m_pManager->FindEntitySafe ( pColEntity ); CLuaArguments Arguments; if ( pClientEntity ) Arguments.PushElement ( pClientEntity ); // entity that got hit else Arguments.PushNil ( ); // Probably a building. Arguments.PushNumber ( pColPoint->GetPosition ( ).fX ); // pos x Arguments.PushNumber ( pColPoint->GetPosition ( ).fY ); // pos y Arguments.PushNumber ( pColPoint->GetPosition ( ).fZ ); // pos z Arguments.PushNumber ( pColPoint->GetNormal ( ).fX ); // Normal x Arguments.PushNumber ( pColPoint->GetNormal ( ).fY ); // Normal y Arguments.PushNumber ( pColPoint->GetNormal ( ).fZ ); // Normal z Arguments.PushNumber ( pColPoint->GetSurfaceTypeB ( ) ); // Surface type "B" Arguments.PushNumber ( pColPoint->GetLightingForTimeOfDay ( ) ); // Lighting Arguments.PushNumber ( pColPoint->GetPieceTypeB ( ) ); // Piece if ( !CallEvent ( "onClientWeaponFire", Arguments, true ) ) { if ( pColPoint ) pColPoint->Destroy (); return; } DoGunShells ( vecOrigin, vecDirection ); CVector vecCollision; if ( g_pGame->GetWaterManager ()->TestLineAgainstWater ( vecOrigin, vecTarget, &vecCollision ) ) { g_pGame->GetFx ()->TriggerBulletSplash ( vecCollision ); g_pGame->GetAudioEngine ()->ReportBulletHit ( NULL, SURFACE_TYPE_WATER_SHALLOW, &vecCollision, 0.0f ); } #ifdef MARKER_DEBUG m_pMarker2->SetPosition ( vecTarget ); #endif m_pWeapon->DoBulletImpact ( m_pObject, pEntity, &vecOrigin, &vecTarget, pColPoint, 0 ); if ( !IsLocalEntity ( ) && m_pOwner ) { CClientPed * pPed = m_pOwner; CClientPed * pLocalPlayer = g_pClientGame->GetLocalPlayer(); if ( pPed->GetType () == CCLIENTPLAYER ) { // Restore compensated positions if ( !pPed->IsLocalPlayer () ) { CClientVehicle* pVehicle = pLocalPlayer->GetRealOccupiedVehicle (); if ( !pVehicle ) { pLocalPlayer->SetPosition ( vecWeaponFirePosition, false, false ); } else if ( pLocalPlayer->GetOccupiedVehicleSeat() == 0 ) { pVehicle->SetPosition ( vecWeaponFirePosition, false, false ); } } } } if ( !IsLocalEntity ( ) && GetOwner ( ) == g_pClientGame->GetLocalPlayer ( ) && bServerFire == false ) { g_pClientGame->GetNetAPI ( )->SendBulletSyncCustomWeaponFire ( this, vecOrigin, vecOriginalTarget ); } } #ifdef SHOTGUN_TEST else { //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( true ); //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( false ); // Fire instant hit is off by a few degrees FireShotgun ( m_pObject, vecOrigin, vecTarget, vecRotation ); } #endif if ( pColPoint ) pColPoint->Destroy (); }
void CScriptDebugging::LogString ( const char* szPrePend, lua_State* luaVM, const char* szMessage, unsigned int uiMinimumDebugLevel, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue ) { SString strText; lua_Debug debugInfo; // Initialize values for onClientDebugMessage SString strMsg = szMessage; SString strFile = ""; int iLine = -1; // Get a VM from somewhere if ( !luaVM && !m_LuaMainStack.empty () ) luaVM = m_LuaMainStack.back ()->GetVM (); for ( int level = 1; level < 3; level++ ) { if ( luaVM && lua_getstack ( luaVM, level, &debugInfo ) ) { lua_getinfo ( luaVM, "nlS", &debugInfo ); // Make sure this function isn't defined in a string (eg: from runcode) if ( debugInfo.source[0] == '@' ) { // Get and store the location of the debug message strFile = debugInfo.source + 1; iLine = debugInfo.currentline; // Populate a message to print/send (unless "info" type) if ( uiMinimumDebugLevel < 3 ) strText = SString ( "%s%s:%d: %s", szPrePend, strFile.c_str (), debugInfo.currentline, szMessage ); // if the file isn't empty, stop trying any other levels break; } else { strFile = debugInfo.short_src; if ( uiMinimumDebugLevel < 3 ) strText = SString ( "%s%s %s", szPrePend, szMessage, strFile.c_str () ); if ( strFile != "[string \"?\"]" ) // if the file isn't empty, stop trying any other levels break; } } else { strText = SString ( "%s%s", szPrePend, szMessage ); // no point in trying other levels break; } } // Create a different message if type is "INFO" if ( uiMinimumDebugLevel > 2 ) strText = SString ( "%s%s", szPrePend, szMessage ); if ( !m_bTriggeringOnClientDebugMessage ) { m_bTriggeringOnClientDebugMessage = true; // Prepare onClientDebugMessage CLuaArguments Arguments; Arguments.PushString ( strMsg.c_str ( ) ); Arguments.PushNumber ( uiMinimumDebugLevel ); // Push the file name (if any) if ( strFile.length ( ) > 0 ) Arguments.PushString ( strFile.c_str ( ) ); else Arguments.PushNil ( ); // Push the line (if any) if ( iLine > -1 ) Arguments.PushNumber ( iLine ); else Arguments.PushNil ( ); // Call onClientDebugMessage g_pClientGame->GetRootEntity ( )->CallEvent ( "onClientDebugMessage", Arguments, false ); m_bTriggeringOnClientDebugMessage = false; } // Log it to the file if enough level if ( m_uiLogFileLevel >= uiMinimumDebugLevel ) { PrintLog ( strText ); } switch ( uiMinimumDebugLevel ) { case 1: ucRed = 255, ucGreen = 0, ucBlue = 0; break; case 2: ucRed = 255, ucGreen = 128, ucBlue = 0; break; case 3: ucRed = 0, ucGreen = 255, ucBlue = 0; break; } #ifdef MTA_DEBUG if ( !g_pCore->IsDebugVisible () ) return; #endif g_pCore->DebugEchoColor ( strText, ucRed, ucGreen, ucBlue ); }
void CScriptDebugging::LogString ( const char* szPrePend, const SLuaDebugInfo& luaDebugInfo, const char* szMessage, unsigned int uiMinimumDebugLevel, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue ) { SString strText = ComposeErrorMessage( szPrePend, luaDebugInfo, szMessage ); // Create a different message if type is "INFO" if ( uiMinimumDebugLevel > 2 ) strText = SString ( "%s%s", szPrePend, szMessage ); // Check whether onDebugMessage is currently being triggered if ( !m_bTriggeringOnDebugMessage ) { // Make sure the state of onDebugMessage being triggered can be retrieved later m_bTriggeringOnDebugMessage = true; // Prepare onDebugMessage CLuaArguments Arguments; Arguments.PushString ( szMessage ); Arguments.PushNumber ( uiMinimumDebugLevel ); // Push the file name (if any) if ( !luaDebugInfo.strFile.empty() ) Arguments.PushString ( luaDebugInfo.strFile ); else Arguments.PushNil ( ); // Push the line (if any) if ( luaDebugInfo.iLine != INVALID_LINE_NUMBER ) Arguments.PushNumber ( luaDebugInfo.iLine ); else Arguments.PushNil ( ); // Call onDebugMessage g_pGame->GetMapManager ( )->GetRootElement ( )->CallEvent ( "onDebugMessage", Arguments ); // Reset trigger state, so onDebugMessage can be called again at a later moment m_bTriggeringOnDebugMessage = false; } // Log it to the file if enough level if ( m_uiLogFileLevel >= uiMinimumDebugLevel ) { PrintLog ( strText ); } // Log to console CLogger::LogPrintf( "%s\n", strText.c_str () ); #if 0 // Not sure what this is for, seems pretty useless if ( m_uiHtmlLogLevel >= uiMinimumDebugLevel ) { if ( luaVM ) { CLuaMain* pLuaMain = g_pGame->GetLuaManager()->GetVirtualMachine ( luaVM ); if ( pLuaMain ) { CResourceFile * file = pLuaMain->GetResourceFile(); if ( file && file->GetType() == CResourceHTMLItem::RESOURCE_FILE_TYPE_HTML ) { CResourceHTMLItem * html = (CResourceHTMLItem *)file; html->AppendToPageBuffer ( strText ); html->AppendToPageBuffer ( "<br/>" ); } } } } #endif // Tell the players Broadcast ( CDebugEchoPacket ( strText, uiMinimumDebugLevel, ucRed, ucGreen, ucBlue ), uiMinimumDebugLevel ); }
void CClientWeapon::FireInstantHit ( CVector & vecOrigin, CVector & vecTarget ) #endif { CVector vecDirection = vecTarget - vecOrigin; vecDirection.Normalize (); CClientEntity * pAttachedTo = GetAttachedTo (); CEntity * pColEntity = NULL; CColPoint * pColPoint = NULL; SLineOfSightBuildingResult pBuildingResult; CEntitySAInterface * pEntity = NULL; if ( m_Type != WEAPONTYPE_SHOTGUN ) { //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( true ); if ( m_pWeapon->ProcessLineOfSight ( &vecOrigin, &vecTarget, &pColPoint, &pColEntity, m_weaponConfig.flags, &pBuildingResult, m_Type, &pEntity ) ) { vecTarget = pColPoint->GetPosition (); } // Don't continue without a valid colpoint if ( !pColPoint ) return; //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( false ); // return if shoot if target is blocked is false and we aren't pointing at our target if ( ( m_pTarget != NULL && m_pTarget->GetGameEntity ( ) != NULL && m_pTarget->GetGameEntity()->GetInterface ( ) != pEntity ) && m_weaponConfig.bShootIfTargetBlocked == false ) { return; } // Execute our weapon fire event CClientEntity * pClientEntity = m_pManager->FindEntitySafe ( pColEntity ); CLuaArguments Arguments; if ( pClientEntity ) Arguments.PushElement ( pClientEntity ); // entity that got hit else Arguments.PushNil ( ); // Probably a building. Arguments.PushNumber ( pColPoint->GetPosition ( ).fX ); // pos x Arguments.PushNumber ( pColPoint->GetPosition ( ).fY ); // pos y Arguments.PushNumber ( pColPoint->GetPosition ( ).fZ ); // pos z Arguments.PushNumber ( pColPoint->GetNormal ( ).fX ); // Normal x Arguments.PushNumber ( pColPoint->GetNormal ( ).fY ); // Normal y Arguments.PushNumber ( pColPoint->GetNormal ( ).fZ ); // Normal z Arguments.PushNumber ( pColPoint->GetSurfaceTypeB ( ) ); // Surface type "B" Arguments.PushNumber ( pColPoint->GetLightingForTimeOfDay ( ) ); // Lighting Arguments.PushNumber ( pColPoint->GetPieceTypeB ( ) ); // Piece if ( !CallEvent ( "onClientWeaponFire", Arguments, true ) ) { return; } DoGunShells ( vecOrigin, vecDirection ); CVector vecCollision; if ( g_pGame->GetWaterManager ()->TestLineAgainstWater ( vecOrigin, vecTarget, &vecCollision ) ) { g_pGame->GetFx ()->TriggerBulletSplash ( vecCollision ); g_pGame->GetAudioEngine ()->ReportBulletHit ( NULL, SURFACE_TYPE_WATER_SHALLOW, &vecCollision, 0.0f ); } #ifdef MARKER_DEBUG m_pMarker2->SetPosition ( vecTarget ); #endif m_pWeapon->DoBulletImpact ( m_pObject, pEntity, &vecOrigin, &vecTarget, pColPoint, 0 ); if ( pColEntity && pColEntity->GetEntityType () == ENTITY_TYPE_PED ) { ePedPieceTypes hitZone = ( ePedPieceTypes ) pColPoint->GetPieceTypeB (); short sDamage = m_pWeaponInfo->GetDamagePerHit (); m_pWeapon->GenerateDamageEvent ( dynamic_cast < CPed * > ( pColEntity ), m_pObject, m_Type, sDamage, hitZone, 0 ); } } #ifdef SHOTGUN_TEST else { //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( true ); //if ( pAttachedTo ) pAttachedTo->WorldIgnore ( false ); // Fire instant hit is off by a few degrees FireShotgun ( m_pObject, vecOrigin, vecTarget, vecRotation ); } #endif if ( pColPoint ) pColPoint->Destroy (); }