[ComponentEditorProps(category: "GameScripted/", description: "Voice Range Controller (Per Meter)")] class SCR_VoiceRangeControllerClass: ScriptComponentClass {} class SCR_VoiceRangeController: ScriptComponent { [Attribute("25", UIWidgets.Slider, "Start-Reichweite in Metern", "1 100 1")] protected int m_iCurrentRange; [Attribute("1", UIWidgets.Slider, "Minimale Reichweite", "1 100 1")] protected int m_iMinRange; [Attribute("100", UIWidgets.Slider, "Maximale Reichweite", "1 100 1")] protected int m_iMaxRange; [Attribute("1", UIWidgets.Slider, "Schrittgröße (Meter pro Tastendruck)", "1 50 1")] protected int m_iStepSize; protected ref Shape m_RangeCircleShape; static SCR_VoiceRangeController GetInstance() { if (!GetGame().GetPlayerController()) return null; return SCR_VoiceRangeController.Cast(GetGame().GetPlayerController().FindComponent(SCR_VoiceRangeController)); } void SCR_VoiceRangeController(IEntityComponentSource src, IEntity ent, IEntity parent) { SetEventMask(ent, EntityEvent.INIT); } protected override void EOnInit(IEntity owner) { if (!GetGame().GetInputManager()) return; // Die Actions, die aufgerufen werden, wenn du + oder - drückst GetGame().GetInputManager().AddActionListener("SCR_VoiceRangeUp", EActionTrigger.DOWN, IncreaseRange); GetGame().GetInputManager().AddActionListener("SCR_VoiceRangeDown", EActionTrigger.DOWN, DecreaseRange); } void IncreaseRange() { ChangeRange(1); } void DecreaseRange() { ChangeRange(-1); } void ChangeRange(int direction) { // Berechnet die neue Reichweite basierend auf der Schrittgröße int newRange = Math.ClampInt(m_iCurrentRange + (direction * m_iStepSize), m_iMinRange, m_iMaxRange); // Nichts tun, wenn das Limit bereits erreicht ist if (m_iCurrentRange == newRange) return; m_iCurrentRange = newRange; ApplyRangeToVON(); UpdateUI(); DrawRangeCircle(); } protected void ApplyRangeToVON() { IEntity player = GetGame().GetPlayerController().GetControlledEntity(); if (!player) return; SCR_VONController vonContr = SCR_VONController.Cast(GetOwner().FindComponent(SCR_VONController)); if (!vonContr) return; // --- HYBRID LÖSUNG --- // Da die Engine "pro Meter" im echten Voice-Chat nicht zulässt, // ordnen wir die Meterzahl im Hintergrund den 3 Komponenten zu. typename compType = SCR_VoNNormal; // Standard if (m_iCurrentRange <= 15) { compType = SCR_VoNWhispering; } else if (m_iCurrentRange >= 50) { compType = SCR_VoNLoud; } SCR_VoNComponent newVonComp = SCR_VoNComponent.Cast(player.FindComponent(compType)); if (newVonComp) { vonContr.SetVONComponent(newVonComp); } } void UpdateUI() { SCR_HUDManagerComponent hud = SCR_HUDManagerComponent.Cast(GetOwner().FindComponent(SCR_HUDManagerComponent)); if (!hud) return; SCR_VoiceRangeDisplay display = SCR_VoiceRangeDisplay.Cast(hud.FindInfoDisplay(SCR_VoiceRangeDisplay)); if (display) { // Übergibt die exakte Meterzahl an dein UI display.UpdateRangeText(m_iCurrentRange); } } void DrawRangeCircle() { IEntity player = GetGame().GetPlayerController().GetControlledEntity(); if (!player) return; if (m_RangeCircleShape) { m_RangeCircleShape = null; } vector mat[4]; player.GetTransform(mat); vector boundsMin, boundsMax; player.GetBounds(boundsMin, boundsMax); mat[3][1] = mat[3][1] + boundsMin[1] + 0.1; int color = ARGB(200, 50, 150, 255); // Zeichnet den Kreis mit dem exakten Radius in Metern (m_iCurrentRange) m_RangeCircleShape = Shape.CreateCylinder(color, ShapeFlags.WIREFRAME | ShapeFlags.TRANSP, mat, m_iCurrentRange, 0.05); GetGame().GetCallqueue().Remove(HideRangeCircle); GetGame().GetCallqueue().CallLater(HideRangeCircle, 2000, false); } void HideRangeCircle() { m_RangeCircleShape = null; } }