//------------------------------------------------------------------------
void CGameRulesHoldObjectiveBase::ReadAudioSignal( const XmlNodeRef node, const char* name, CAudioSignalPlayer* signalPlayer )
{
	if(node->haveAttr(name))
	{
		char signalName[32];
		cry_strcpy(signalName, node->getAttr(name));
		signalPlayer->SetSignal(signalName);
	}
}
//------------------------------------------------------------------------
void CGameRulesHoldObjectiveBase::ReadAudioSignal( const XmlNodeRef node, const char* name, CAudioSignalPlayer* signalPlayer )
{
	if(node->haveAttr(name))
	{
		const static int k_maxAudioSignalLength = 32;
		char signalName[k_maxAudioSignalLength];
		cry_strncpy(signalName, node->getAttr(name), k_maxAudioSignalLength);
		signalPlayer->SetSignal(signalName);
	}
}
Esempio n. 3
0
CItemParamsNode::EXMLFilterType CItemParamsNode::ShouldConvertNodeFromXML(const XmlNodeRef &xmlNode, const char * keepWithThisAttrValue) const
{
	if(xmlNode->haveAttr("GAME"))
	{
		const char * game = xmlNode->getAttr("GAME");

		return (strcmp(game, keepWithThisAttrValue) == 0 ? eXMLFT_add : eXMLFT_remove);
	}

	return eXMLFT_none;
}
Esempio n. 4
0
//------------------------------------------------------------------------
bool CPlayerProfileImplFS::LoginUser(SUserEntry* pEntry)
{
	// lookup stored profiles of the user (pEntry->userId) and fill in the pEntry->profileDesc
	// vector 
	pEntry->profileDesc.clear();

	// scan directory for profiles

	string path;
	InternalMakeFSPath(pEntry, "", path);  // no profile name -> only path

	ICryPak * pCryPak = gEnv->pCryPak;
	_finddata_t fd;

	path.TrimRight("/\\");
	string search = path + "/*.xml";
	intptr_t handle = pCryPak->FindFirst( search.c_str(), &fd );
	if (handle != -1)
	{
		do
		{
			// fd.name contains the profile name
			string filename = path;
			filename += "/" ;
			filename += fd.name;
			XmlNodeRef rootNode = LoadXMLFile(filename.c_str());

			// see if the root tag is o.k.
			if (rootNode && stricmp(rootNode->getTag(), PROFILE_ROOT_TAG) == 0)
			{
				string profileName = fd.name;
				PathUtil::RemoveExtension(profileName);
				if (rootNode->haveAttr(PROFILE_NAME_TAG))
				{
					const char* profileHumanName = rootNode->getAttr(PROFILE_NAME_TAG);
					if (profileHumanName!=0 && stricmp(profileHumanName, profileName) == 0)
					{
						profileName = profileHumanName;
					}
				}
				pEntry->profileDesc.push_back(SLocalProfileInfo(profileName));
			}
			else
			{
				GameWarning("CPlayerProfileImplFS::LoginUser: Profile '%s' of User '%s' seems to exist, but is invalid (File '%s). Skipped", fd.name, pEntry->userId.c_str(), filename.c_str());
			}
		} while ( pCryPak->FindNext( handle, &fd ) >= 0 );

		pCryPak->FindClose( handle );
	}

	return true;
}
void CVehicleModificationParams::InitModificationElem( XmlNodeRef xmlElem )
{
	assert( m_pImpl != NULL );
	assert( xmlElem != (IXmlNode*)NULL );

	bool valid = true;
	valid &= xmlElem->haveAttr( "idRef" );
	valid &= xmlElem->haveAttr( "name" );
	valid &= xmlElem->haveAttr( "value" );

	if ( ! valid )
	{
		CryLog( "Vehicle modification element at line %i invalid, skipping.", xmlElem->getLine() );
		return;
	}

	const char* id = xmlElem->getAttr( "idRef" );
	const char* attrName = xmlElem->getAttr( "name" );

	Implementation::TModificationKey key( id, attrName );
	m_pImpl->m_modifications[ key ] = xmlElem;
}
void CForceFeedBackSystem::LoadEnvelopes( XmlNodeRef& envelopesNode )
{
	const int envelopesCount = envelopesNode->getChildCount();

	m_envelopes.reserve(envelopesCount);

	TSamplesBuffer samplesBuffer;
	const int maxSampleCount = FFSYSTEM_MAX_ENVELOPE_SAMPLES / 2;
	float readValues[maxSampleCount];

	for (int i = 0; i < envelopesCount; ++i)
	{
		XmlNodeRef envelopeChildNode = envelopesNode->getChild(i);

		const char* customEnvelopeName = envelopeChildNode->getAttr("name");
		if (!customEnvelopeName || (customEnvelopeName[0] == '\0'))
		{
			FORCEFEEDBACK_LOG("Could not load envelope without name (at line %d)", envelopeChildNode->getLine());
			continue;
		}

		samplesBuffer = envelopeChildNode->haveAttr("name") ? envelopeChildNode->getAttr("samples") : "";

		int samplesFound = ParseSampleBuffer(samplesBuffer, &readValues[0], maxSampleCount);

		if (samplesFound != 0)
		{
			SEnvelope customEnvelope;
			customEnvelope.ResetToDefault();

			DistributeSamples(&readValues[0], samplesFound, &customEnvelope.m_envelopeSamples[0], FFSYSTEM_MAX_ENVELOPE_SAMPLES);

			customEnvelope.m_envelopeId.Set(customEnvelopeName);
			m_envelopes.push_back(customEnvelope);
		}
		else
		{
			FORCEFEEDBACK_LOG("Envelope '%s' (at line %d) has not samples, skipping", customEnvelopeName, envelopeChildNode->getLine());
		}
	}

	std::sort(m_envelopes.begin(), m_envelopes.end());
}
void CForceFeedBackSystem::LoadPatters( XmlNodeRef& patternsNode )
{
	const int patterCount = patternsNode->getChildCount();

	m_patters.reserve(patterCount);

	TSamplesBuffer samplesBuffer;
	const int maxSampleCount = FFSYSTEM_MAX_PATTERN_SAMPLES / 2;
	float readValues[maxSampleCount];

	for (int i = 0; i < patterCount; ++i)
	{
		XmlNodeRef childPatternNode = patternsNode->getChild(i);

		const char* customPatternName = childPatternNode->getAttr("name");
		if (!customPatternName || (customPatternName[0] == '\0'))
		{
			FORCEFEEDBACK_LOG("Could not load pattern without name (at line %d)", childPatternNode->getLine());
			continue;
		}

		samplesBuffer = childPatternNode->haveAttr("name") ? childPatternNode->getAttr("samples") : "";

		int samplesFound = ParseSampleBuffer(samplesBuffer, &readValues[0], maxSampleCount);

		if (samplesFound != 0)
		{
			SPattern customPattern;
			customPattern.ResetToDefault();

			DistributeSamples(&readValues[0], samplesFound, &customPattern.m_patternSamples[0], FFSYSTEM_MAX_PATTERN_SAMPLES);

			customPattern.m_patternId.Set(customPatternName);
			m_patters.push_back(customPattern);
		}
		else
		{
			FORCEFEEDBACK_LOG("Pattern '%s' (at line %d) has not samples, skipping", customPatternName, childPatternNode->getLine());
		}
	}

	std::sort(m_patters.begin(), m_patters.end());
}
//------------------------------------------------------------------------
void CGameRulesKingOfTheHillObjective::Init( XmlNodeRef xml )
{
	BaseType::Init(xml);

	if (xml->getAttr("scoreTime", m_scoreTimerMaxLength))
	{
		CryLog("CGameRulesKingOfTheHillObjective::Init, using score timer, length=%f", m_scoreTimerMaxLength);
	}
	xml->getAttr("additionalPlayerTimerMultiplier", m_scoreTimerAdditionalPlayerMultiplier);
	if (m_scoreTimerAdditionalPlayerMultiplier == 0.f)
	{
		m_scoreTimerAdditionalPlayerMultiplier = 1.f;
	}
	CryLog("CGameRulesKingOfTheHillObjective::Init, multiplier for additional players=%f", m_scoreTimerAdditionalPlayerMultiplier);

	int numChildren = xml->getChildCount();
	for (int childIdx = 0; childIdx < numChildren; ++ childIdx)
	{
		XmlNodeRef xmlChild = xml->getChild(childIdx);
		const char *pTag = xmlChild->getTag();
		if (!stricmp(pTag, "Icons"))
		{
			CRY_ASSERT_MESSAGE(!m_useIcons, "KingOfTheHillObjective xml contains more than one 'Icons' node, we only support one");
			m_useIcons = true;

			m_neutralIcon   = SGameRulesMissionObjectiveInfo::GetIconId(xmlChild->getAttr("neutral"));
			m_friendlyIcon  = SGameRulesMissionObjectiveInfo::GetIconId(xmlChild->getAttr("friendly"));
			m_hostileIcon   = SGameRulesMissionObjectiveInfo::GetIconId(xmlChild->getAttr("hostile"));
			m_contestedIcon = SGameRulesMissionObjectiveInfo::GetIconId(xmlChild->getAttr("contested"));

			m_shouldShowIconFunc.Format("%s", xmlChild->getAttr("checkFunc"));

			CryLog("CGameRulesKingOfTheHillObjective::Init, using on-screen icons [%i %i %i %i]", m_neutralIcon, m_friendlyIcon, m_hostileIcon, m_contestedIcon);
		}
		else if(strcmp(pTag,"Audio") == 0)
		{
			if(xmlChild->haveAttr("capturedLoop"))
			{
				m_captureSignalId = g_pGame->GetGameAudio()->GetSignalID(xmlChild->getAttr("capturedLoop"));
			}
		}
		else if (!stricmp(pTag, "Strings"))
		{
			const char *pString = 0;
			if (xmlChild->getAttr("friendlyCapture", &pString))
			{
				m_friendlyCaptureString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("enemyCapture", &pString))
			{
				m_enemyCaptureString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("friendlyLost", &pString))
			{
				m_friendlyLostString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("enemyLost", &pString))
			{
				m_enemyLostString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("newEntity", &pString))
			{
				m_newEntityString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("gameStateNeutral", &pString))
			{
				m_gameStateNeutralString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("gameStateFriendly", &pString))
			{
				m_gameStateFriendlyString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("gameStateEnemy", &pString))
			{
				m_gameStateEnemyString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("gameStateDestructing", &pString))
			{
				m_gameStateDestructingString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("gameStateIncoming", &pString))
			{
				m_gameStateIncomingString.Format("@%s", pString);
			}
			if (xmlChild->getAttr("iconTextDefend", &pString))
			{
				m_iconTextDefend.Format("@%s", pString);
				m_iconTextDefend = CHUDUtils::LocalizeString(m_iconTextDefend.c_str());
			}
			if (xmlChild->getAttr("iconTextClear", &pString))
			{
				m_iconTextClear.Format("@%s", pString);
				m_iconTextClear = CHUDUtils::LocalizeString(m_iconTextClear.c_str());
			}
			if (xmlChild->getAttr("iconTextCapture", &pString))
			{
				m_iconTextCapture.Format("@%s", pString);
				m_iconTextCapture = CHUDUtils::LocalizeString(m_iconTextCapture.c_str());
			}
		}
		else if (!stricmp(pTag, "RadiusPulse"))
		{
			xmlChild->getAttr("time", m_pulseTimerLength);
			m_shouldDoPulseEffectFunc.Format("%s", xmlChild->getAttr("checkFunc"));
		}
	}
}
bool CommunicationVoiceLibrary::LoadFromFile(const char* fileName)
{
	MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "Communication Voice Library" );
	MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_Other, 0, "Voice Lib: %s",fileName );

	XmlNodeRef root = GetISystem()->LoadXmlFromFile(fileName);
	if (!root)
		return false;

	XmlNodeRef nodeWorksheet = root->findChild("Worksheet");
	if (!nodeWorksheet)
		return false;

	XmlNodeRef nodeTable = nodeWorksheet->findChild("Table");
	if (!nodeTable)
		return false;

	stack_string libName(PathUtil::GetFileName(fileName));

	VoiceLibraryID libraryID = GetVoiceLibraryID(libName.c_str());

	std::pair<VoiceLibraries::iterator, bool> iresult = m_libraries.insert(
		VoiceLibraries::value_type(libraryID, VoiceLibrary()));

	if (!iresult.second)
	{
		if (iresult.first->second.name == libName.c_str())
		{
			AIWarningID("<AICommunicationVoiceLibrary::LoadFromFile> ", 
				"Duplicate voice library '%s'!", libName.c_str());

			return false;
		}
		else
		{
			AIWarningID("<AICommunicationVoiceLibrary::LoadFromFile> ", 
				"Hash collision for voice library name '%s' and '%s'!", libName.c_str(), iresult.first->second.name.c_str());

			return false;
		}
	}

	VoiceLibrary& library = iresult.first->second;
	library.name = string(libName);
	
	VoiceGroup* voiceGroup = 0;
		
	string signalName;
	string lastSignalName;
	string voiceName;

	for (int rowCntr = 0, childN = 0; childN < nodeTable->getChildCount(); ++childN)
	{
		XmlNodeRef nodeRow = nodeTable->getChild(childN);
		if (!nodeRow->isTag("Row"))
			continue;

		++rowCntr;
		if (rowCntr == 1) // skip language
			continue;

		if (rowCntr == 2) // path
		{
			int cellN = 0;
			for (int childrenCntr = 0; childrenCntr < nodeRow->getChildCount(); ++childrenCntr)
			{
				XmlNodeRef nodeCell = nodeRow->getChild(childrenCntr);
				if (!nodeCell->isTag("Cell"))
					continue;

				++cellN;
				if (cellN == 2)
				{
					XmlNodeRef nodeCellData = nodeCell->findChild("Data");
					if (!nodeCellData)
						break;

					library.base = PathUtil::GetLocalizationFolder() + nodeCellData->getContent();
					if (!library.base.empty())
					{
						library.base.replace("\\", "/");
						if (library.base[library.base.length()-1] != '/')
							library.base.append("/");
					}
					break;
				}
			}
			continue;
		}

		if (rowCntr == 3) // headers
			continue;

		signalName.clear();
		voiceName.clear();
		
		for (int childrenCntr = 0, cellIndex = 1; childrenCntr < nodeRow->getChildCount(); ++childrenCntr, ++cellIndex)
		{
			XmlNodeRef nodeCell = nodeRow->getChild(childrenCntr);
			if (!nodeCell->isTag("Cell"))
				continue;

			if (nodeCell->haveAttr("ss:Index"))
			{
				const char* strIdx = nodeCell->getAttr("ss:Index");
				if (sscanf(strIdx, "%d", &cellIndex) != 1)
					continue;
			}

			XmlNodeRef nodeCellData = nodeCell->findChild("Data");
			if (!nodeCellData)
				continue;

			switch (cellIndex)
			{
			case 1:
				signalName = nodeCellData->getContent();
				break;
			case 2:
				voiceName = nodeCellData->getContent();
				break;
			}
		}

		if (!signalName.empty())
		{
			signalName.MakeLower();
			std::pair<VoiceGroups::iterator, bool> itresult = library.voiceGroups.insert(
				VoiceGroups::value_type(signalName, VoiceGroup()));

			voiceGroup = &itresult.first->second;
			// The 20 here comes from inspection of the resulting contents in memreplay
			voiceGroup->variations.reserve(20);

			if (!itresult.second)
			{
				if (lastSignalName != signalName)
					AIWarningID("<AICommunicationVoiceLibrary::LoadFromFile> ", 
						"Duplicate voice signal '%s' in file '%s'.", signalName.c_str(), libName.c_str());
			}

			lastSignalName = signalName;
		}

		if (!voiceGroup || voiceName.empty())
			continue;

		if ((library.base.find_first_of(':') == string::npos) && (voiceName.find_first_of(':') == string::npos))
			voiceName.append(".wav");

		if (voiceGroup->variations.size() < MaxVariationCount)
			voiceGroup->variations.push_back(voiceName);
		else
			AIWarningID("<AICommunicationVoiceLibrary::LoadFromFile> ", 
			"Too many voice variations for signal '%s' in file '%s'. Limit is 32.", signalName.c_str(), libName.c_str());
	}

	return true;
}
void CForceFeedBackSystem::LoadEffects( XmlNodeRef& effectsNode )
{
	CGameXmlParamReader paramReader(effectsNode);
	const int effectsCount = paramReader.GetUnfilteredChildCount();

	m_effectToIndexMap.reserve(effectsCount);
	m_effects.reserve(effectsCount);
	m_effectNames.reserve(effectsCount);

	for (int i = 0; i < effectsCount; ++i)
	{
		XmlNodeRef childEffectNode = paramReader.GetFilteredChildAt(i);

		if( childEffectNode )
		{
			SEffect newEffect;
			const int effectDataCount = childEffectNode->getChildCount();

			const char* effectName = childEffectNode->getAttr("name");

			//Check for invalid name
			if ((effectName == NULL) || (effectName[0] == '\0'))
			{
				FORCEFEEDBACK_LOG("Could not load effect without name (at line %d)", childEffectNode->getLine());
				continue;
			}

			//Check for duplicates
			if (m_effectToIndexMap.find(FFBInternalId::GetIdForName(effectName)) != m_effectToIndexMap.end())
			{
				FORCEFEEDBACK_LOG("Effect '%s' does already exists, skipping", effectName);
				continue;
			}

			childEffectNode->getAttr("time", newEffect.time);	

			for (int j = 0; j < effectDataCount; ++j)
			{
				XmlNodeRef motorNode = childEffectNode->getChild(j);

				const char* motorTag = motorNode->getTag();

				if (strcmp(motorTag, "MotorAB") == 0)
				{
					newEffect.patternA.Set( motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "" );
					newEffect.patternB = newEffect.patternA;
					newEffect.envelopeA.Set( motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "" );
					newEffect.envelopeB = newEffect.envelopeA;
					motorNode->getAttr("frequency", newEffect.frequencyA);
					newEffect.frequencyB = newEffect.frequencyA;
				}
				else if (strcmp(motorTag, "MotorA") == 0)
				{
					newEffect.patternA.Set( motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "" );
					newEffect.envelopeA.Set( motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "" );
					motorNode->getAttr("frequency", newEffect.frequencyA);
				}
				else if (strcmp(motorTag, "MotorB") == 0)
				{
					newEffect.patternB.Set( motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "" );
					newEffect.envelopeB.Set( motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "" );
					motorNode->getAttr("frequency", newEffect.frequencyB);
				}
			}

			newEffect.frequencyA = (float)__fsel(-newEffect.frequencyA, 1.0f, newEffect.frequencyA);
			newEffect.frequencyB = (float)__fsel(-newEffect.frequencyB, 1.0f, newEffect.frequencyB);

			m_effects.push_back(newEffect);
			m_effectNames.push_back(effectName);

			FFBInternalId internalId;
			internalId.Set(effectName);
			m_effectToIndexMap.insert(TEffectToIndexMap::value_type(internalId, ((int)m_effects.size() - 1)));
		}
	}
}
Esempio n. 11
0
//------------------------------------------------------------------------
bool CPlayerProfileImplFSDir::LoginUser(SUserEntry* pEntry)
{
	// lookup stored profiles of the user (pEntry->userId) and fill in the pEntry->profileDesc
	// vector 
	pEntry->profileDesc.clear();

	// scan directory for profiles

	string path;
	InternalMakeFSPath(pEntry, "", path);  // no profile name -> only path

	std::multimap<time_t, SLocalProfileInfo> profiles;

	ICryPak * pCryPak = gEnv->pCryPak;
	_finddata_t fd;

	path.TrimRight("/\\");
	string search = path + "/*.*";

	IPlatformOS* pOS = GetISystem()->GetPlatformOS();
	IPlatformOS::IFileFinderPtr fileFinder = pOS->GetFileFinder(IPlatformOS::Unknown_User);
	intptr_t handle = fileFinder->FindFirst(search.c_str(), &fd);
	if (handle != -1)
	{
		do
		{
			if (strcmp(fd.name, ".") == 0 || strcmp(fd.name, "..") == 0)
				continue;

			if (fd.attrib & _A_SUBDIR)
			{
				// profile name = folder name
				// but make sure there is a profile.xml in it
				string filename = path + "/" + fd.name;
				filename += "/" ;
				filename += "profile.xml";
				XmlNodeRef rootNode = LoadXMLFile(filename.c_str());

				// see if the root tag is o.k.
				if (rootNode && stricmp(rootNode->getTag(), PROFILE_ROOT_TAG) == 0)
				{
					string profileName = fd.name;
					if (rootNode->haveAttr(PROFILE_NAME_TAG))
					{
						const char* profileHumanName = rootNode->getAttr(PROFILE_NAME_TAG);
						if (profileHumanName!=0 && stricmp(profileHumanName, profileName) == 0)
						{
							profileName = profileHumanName;
						}
					}
					time_t time = NULL;
					if (rootNode->haveAttr(PROFILE_LAST_PLAYED))
					{
						rootNode->getAttr(PROFILE_LAST_PLAYED, time);
					}
					SLocalProfileInfo info(profileName);
					info.SetLastLoginTime(time);
					profiles.insert(std::make_pair(time, info));
				}
				else
				{
					GameWarning("CPlayerProfileImplFSDir::LoginUser: Profile '%s' of User '%s' seems to exists but is invalid (File '%s). Skipped", fd.name, pEntry->userId.c_str(), filename.c_str());
				}
			}
		} while ( fileFinder->FindNext( handle, &fd ) >= 0 );

		fileFinder->FindClose( handle );
	}

	// Insert in most recently played order
	std::multimap<time_t, SLocalProfileInfo>::const_reverse_iterator itend = profiles.rend();
	for(std::multimap<time_t, SLocalProfileInfo>::const_reverse_iterator it = profiles.rbegin(); it != itend; ++it)
		pEntry->profileDesc.push_back(it->second);

	return true;
}
TConnectionPtr CAudioSystemEditor_wwise::CreateConnectionFromXMLNode(XmlNodeRef pNode, EACEControlType eATLControlType)
{
    if (pNode)
    {
        const string sTag = pNode->getTag();
        TImplControlType type = TagToType(sTag);
        if (type != AUDIO_IMPL_INVALID_TYPE)
        {
            string sName = pNode->getAttr("wwise_name");
            string sLocalised = pNode->getAttr("wwise_localised");
            bool bLocalised = (sLocalised.compareNoCase("true") == 0);

            // If control not found, create a placeholder.
            // We want to keep that connection even if it's not in the middleware.
            // The user could be using the engine without the wwise project
            IAudioSystemControl* pControl = GetControlByName(sName, bLocalised);
            if (pControl == nullptr)
            {
                pControl = CreateControl(SControlDef(sName, type));
                if (pControl)
                {
                    pControl->SetPlaceholder(true);
                    pControl->SetLocalised(bLocalised);
                }
            }

            // If it's a switch we actually connect to one of the states within the switch
            if (type == eWCT_WWISE_SWITCH_GROUP || type == eWCT_WWISE_GAME_STATE_GROUP)
            {
                if (pNode->getChildCount() == 1)
                {
                    pNode = pNode->getChild(0);
                    if (pNode)
                    {
                        string sChildName = pNode->getAttr("wwise_name");

                        IAudioSystemControl* pChildControl = GetControlByName(sChildName, false, pControl);
                        if (pChildControl == nullptr)
                        {
                            pChildControl = CreateControl(SControlDef(sChildName, type == eWCT_WWISE_SWITCH_GROUP ? eWCT_WWISE_SWITCH : eWCT_WWISE_GAME_STATE, false, pControl));
                        }
                        pControl = pChildControl;
                    }
                }
                else
                {
                    CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_ERROR, "Audio Controls Editor (Wwise): Error reading connection to Wwise control %s", sName);
                }
            }

            if (pControl)
            {
                pControl->SetConnected(true);
                ++m_connectionsByID[pControl->GetId()];

                if (type == eWCT_WWISE_RTPC)
                {
                    switch (eATLControlType)
                    {
                    case EACEControlType::eACET_RTPC:
                    {
                        TRtpcConnectionPtr pConnection = std::make_shared<CRtpcConnection>(pControl->GetId());

                        float mult = 1.0f;
                        float shift = 0.0f;
                        if (pNode->haveAttr("atl_mult"))
                        {
                            const string sProperty = pNode->getAttr("atl_mult");
                            mult = (float)std::atof(sProperty.c_str());
                        }
                        if (pNode->haveAttr("atl_shift"))
                        {
                            const string sProperty = pNode->getAttr("atl_shift");
                            shift = (float)std::atof(sProperty.c_str());
                        }
                        pConnection->fMult = mult;
                        pConnection->fShift = shift;
                        return pConnection;
                    }
                    case EACEControlType::eACET_SWITCH_STATE:
                    {
                        TStateConnectionPtr pConnection = std::make_shared<CStateToRtpcConnection>(pControl->GetId());

                        float value = 0.0f;
                        if (pNode->haveAttr("atl_mult"))
                        {
                            const string sProperty = pNode->getAttr("wwise_value");
                            value = (float)std::atof(sProperty.c_str());
                        }
                        pConnection->fValue = value;
                        return pConnection;
                    }
                    }
                }
                else
                {
                    return std::make_shared<IAudioConnection>(pControl->GetId());
                }
            }
        }
    }
    return nullptr;
}