Files
GTG-VoiceRange/scripts/Game/VON/SCR_VoiceRangeController.c
2026-03-12 20:10:53 +01:00

162 lines
6.1 KiB
C

[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, "Schrittgroesse (Meter pro Tastendruck)", "1 50 1")]
protected int m_iStepSize;
// Speichert das echte Ring-Objekt (Decal) in der Spielwelt
protected IEntity m_RangeRingEntity;
// Timer für den Cooldown (verhindert das +1 / -1 Springen bei analogen Tasten)
protected int m_iLastInputTime = 0;
static SCR_VoiceRangeController GetInstance() {
if (!GetGame().GetPlayerController()) return null;
return SCR_VoiceRangeController.Cast(GetGame().GetPlayerController().FindComponent(SCR_VoiceRangeController));
}
override void OnPostInit(IEntity owner) {
super.OnPostInit(owner);
SetEventMask(owner, EntityEvent.INIT);
}
protected override void EOnInit(IEntity owner) {
if (!GetGame().GetInputManager()) return;
// HIER STEHEN DIE NAMEN DER ACTIONS
GetGame().GetInputManager().AddActionListener("GTG_RangeUp", EActionTrigger.DOWN, IncreaseRange);
GetGame().GetInputManager().AddActionListener("GTG_RangeDown", EActionTrigger.DOWN, DecreaseRange);
}
void IncreaseRange() {
// Blockiert den Input, wenn seit dem letzten Druck nicht mind. 250ms vergangen sind
if (System.GetTickCount() < m_iLastInputTime + 250) return;
m_iLastInputTime = System.GetTickCount(); // Speichert die aktuelle Zeit
Print("GTG Voice: PLUS gedrueckt!", LogLevel.WARNING);
ChangeRange(1);
}
void DecreaseRange() {
// Blockiert den Input auch hier für 250ms
if (System.GetTickCount() < m_iLastInputTime + 250) return;
m_iLastInputTime = System.GetTickCount();
Print("GTG Voice: MINUS gedrueckt!", LogLevel.WARNING);
ChangeRange(-1);
}
void ChangeRange(int direction) {
int newRange = Math.ClampInt(m_iCurrentRange + (direction * m_iStepSize), m_iMinRange, m_iMaxRange);
if (m_iCurrentRange == newRange) return;
m_iCurrentRange = newRange;
Print("GTG Voice: Neue Reichweite ist " + m_iCurrentRange.ToString(), LogLevel.WARNING);
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 ---
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() {
Print("GTG Voice: Suche HUD Manager...", LogLevel.WARNING);
SCR_HUDManagerComponent hud = SCR_HUDManagerComponent.Cast(GetOwner().FindComponent(SCR_HUDManagerComponent));
if (!hud) {
Print("GTG Voice: FEHLER - HUD Manager nicht auf dem PlayerController gefunden!", LogLevel.ERROR);
return;
}
Print("GTG Voice: Suche VoiceRangeDisplay...", LogLevel.WARNING);
SCR_VoiceRangeDisplay display = SCR_VoiceRangeDisplay.Cast(hud.FindInfoDisplay(SCR_VoiceRangeDisplay));
if (!display) {
Print("GTG Voice: FEHLER - SCR_VoiceRangeDisplay fehlt in den Info Displays des HUD Managers!", LogLevel.ERROR);
return;
}
Print("GTG Voice: Display gefunden! Sende Text an UI...", LogLevel.WARNING);
display.UpdateRangeText(m_iCurrentRange);
}
void DrawRangeCircle() {
IEntity player = GetGame().GetPlayerController().GetControlledEntity();
if (!player) {
Print("GTG Voice: FEHLER - Kein spielbarer Charakter (Koerper) fuer den Kreis gefunden!", LogLevel.ERROR);
return;
}
// Wenn schon ein Ring existiert, sofort löschen
if (m_RangeRingEntity) {
SCR_EntityHelper.DeleteEntityAndChildren(m_RangeRingEntity);
m_RangeRingEntity = null;
}
// 1. Hole absolute Welt-Position der Füße
vector playerPos = player.GetOrigin();
// 2. Erstelle Spawn-Parameter
EntitySpawnParams spawnParams = EntitySpawnParams();
spawnParams.TransformMode = ETransformMode.WORLD;
spawnParams.Transform[3] = playerPos;
// 3. Spawne das Decal-Prefab
ResourceName ringPrefab = "{E6268D7D980F8A5D}Prefabs/Props/Military/Compositions/US/Decals/Decal_Helipad_US.et";
Resource res = Resource.Load(ringPrefab);
if (res && res.IsValid()) {
m_RangeRingEntity = GetGame().SpawnEntityPrefab(res, GetGame().GetWorld(), spawnParams);
if (m_RangeRingEntity) {
// Skaliere das Objekt passend zu der Meter-Reichweite
float scale = m_iCurrentRange * 1.0;
m_RangeRingEntity.SetScale(scale);
}
} else {
Print("GTG Voice: Ring Prefab konnte nicht geladen werden!", LogLevel.ERROR);
}
// Nach 2 Sekunden restlos aus der Welt löschen
GetGame().GetCallqueue().Remove(HideRangeCircle);
GetGame().GetCallqueue().CallLater(HideRangeCircle, 2000, false);
}
void HideRangeCircle() {
if (m_RangeRingEntity) {
SCR_EntityHelper.DeleteEntityAndChildren(m_RangeRingEntity);
m_RangeRingEntity = null;
}
}
}