Bug report intresting ansver

bug id : 9929d2a0-5bb3-47f9-8289-e90aa0032536
nt;

public override void OnAppStarted()

{

// Subscribe to animation events

AnimationController.Instance.AnimationEvents.OnOutcomeAnimationFinished.AddListener(OutcomeAnimationFinished);

AnimationController.Instance.AnimationEvents.OnProgressBarFinished.AddListener(ProgressBarFinished);

// Initialize the health animations

healthAnimationsStart = new HealthAnimations();

healthAnimationsOngoing = new HealthAnimations();

healthAnimationsOutcome = new HealthAnimations();

}

public override void OnStateStarted()

{

EncounterController.Instance.StartEncounter();

// Reset health animations

healthAnimationsStart.Clear();

healthAnimationsOngoing.Clear();

healthAnimationsOutcome.Clear();

// Get references

uiEventCounter = FindObjectOfType();

uiOutcome = FindObjectOfType();

// Save the current player health to check at the end if the player died or not

startingPlayerHealth = EncounterController.Instance.Player.CurrentHealth;

// Check if this is the first time we’re starting the encounter

bool isFirstStart = !EncounterSingleton.Instance.IsEventCounterActive;

if (isFirstStart)

{

// This is the first time we’re running this encounter

Debug.Log(“Starting encounter for the first time”);

// Mark the event counter as active so subsequent calls know we’re already running

EncounterSingleton.Instance.IsEventCounterActive = true;

// Play the start animation

AnimationController.Instance.PlayStartAnimation();

// Subscribe to UI event counter events

uiEventCounter.OnReadyButtonPressed.AddListener(ReadyButtonPressed);

// Start health changes for the encounter start effects

ProcessEncounterStartEffects();

}

else

{

// We’re resuming an encounter that was already in progress

Debug.Log(“Resuming encounter that was already in progress”);

// Immediately advance to the next appropriate state based on where we left off

if (EncounterSingleton.Instance.CurrentTurn < EncounterSingleton.Instance.TotalTurns)

{

// We’re still in the middle of the encounter

AdvanceToReadyState();

}

else

{

// The encounter is already over, go straight to outcome

AdvanceToOutcomeState();

}

}

}

private void ProcessEncounterStartEffects()

{

List startEffects = EncounterController.Instance.GetEncounterStartEffects();

if (startEffects.Count > 0)

{

Debug.Log($“Processing {startEffects.Count} encounter start effects”);

// Get all health change effects from the start effects

foreach (EffectData effect in startEffects)

{

if (effect.EffectType == EffectType.PlayerHealth || effect.EffectType == EffectType.EnemyHealth)

{

// Add to start health animations

healthAnimationsStart.AddEffect(effect);

}

}

// Apply all encounter start effects (this actually changes the health values)

EncounterController.Instance.ApplyEffects(startEffects);

// Queue the health animations for the start effects

if (healthAnimationsStart.HasAnimations)

{

AnimationController.Instance.QueueHealthAnimations(healthAnimationsStart);

}

// If we have start animations, they’ll play and we’ll move to the ready state

// after they finish. If not, we move to ready state immediately.

if (!AnimationController.Instance.HasQueuedAnimations)

{

AdvanceToReadyState();

}

}

else

{

// No start effects, move directly to the ready state

AdvanceToReadyState();

}

}

private void ReadyButtonPressed()

{

Debug.Log(“Ready button pressed”);

// Increment the turn counter

EncounterSingleton.Instance.CurrentTurn++;

// Unsubscribe from the ready button event to prevent multiple calls

uiEventCounter.OnReadyButtonPressed.RemoveListener(ReadyButtonPressed);

// Process the turn

ProcessTurn();

}

private void ProcessTurn()

{

int currentTurn = EncounterSingleton.Instance.CurrentTurn;

Debug.Log($“Processing turn {currentTurn}”);

// Reset ongoing health animations for this turn

healthAnimationsOngoing.Clear();

// Get the ongoing effects for this turn and apply them

List ongoingEffects = EncounterController.Instance.GetOngoingEffects();

if (ongoingEffects.Count > 0)

{

Debug.Log($“Processing {ongoingEffects.Count} ongoing effects for turn {currentTurn}”);

// Collect health animations from ongoing effects

foreach (EffectData effect in ongoingEffects)

{

if (effect.EffectType == EffectType.PlayerHealth || effect.EffectType == EffectType.EnemyHealth)

{

// Add to ongoing health animations

healthAnimationsOngoing.AddEffect(effect);

}

}

// Apply all ongoing effects (this actually changes the health values)

EncounterController.Instance.ApplyEffects(ongoingEffects);

}

// Start the progress bar animation

AnimationController.Instance.PlayProgressBarAnimation();

// Queue health animations if we have any

if (healthAnimationsOngoing.HasAnimations)

{

AnimationController.Instance.QueueHealthAnimations(healthAnimationsOngoing);

}

}

private void ProgressBarFinished()

{

Debug.Log(“Progress bar animation finished”);

// Check if we’ve reached the max number of turns

if (EncounterSingleton.Instance.CurrentTurn >= EncounterSingleton.Instance.TotalTurns)

{

AdvanceToOutcomeState();

}

else

{

AdvanceToReadyState();

}

}

private void AdvanceToReadyState()

{

Debug.Log(“Advancing to Ready state”);

// Re-subscribe to the ready button event for the next turn

uiEventCounter.OnReadyButtonPressed.AddListener(ReadyButtonPressed);

// Reset the UI for the next turn

uiEventCounter.SetTurnText(EncounterSingleton.Instance.CurrentTurn + 1, EncounterSingleton.Instance.TotalTurns);

uiEventCounter.ShowReadyButton();

}

private void AdvanceToOutcomeState()

{

Debug.Log(“Advancing to Outcome state”);

// Clear any remaining health animations

healthAnimationsOutcome.Clear();

// Get and apply outcome effects

List outcomeEffects = EncounterController.Instance.GetEncounterOutcomeEffects();

if (outcomeEffects.Count > 0)

{

Debug.Log($“Processing {outcomeEffects.Count} outcome effects”);

// Get all health change effects from the outcome effects

foreach (EffectData effect in outcomeEffects)

{

if (effect.EffectType == EffectType.PlayerHealth || effect.EffectType == EffectType.EnemyHealth)

{

// Add to outcome health animations

healthAnimationsOutcome.AddEffect(effect);

}

}

// Apply all outcome effects (this actually changes the health values)

EncounterController.Instance.ApplyEffects(outcomeEffects);

}

// Determine the outcome

bool playerDied = false;

bool enemyDied = EncounterController.Instance.Enemy.CurrentHealth <= 0;

// Only consider the player to have died if they had health at the start but now they’re at 0

if (startingPlayerHealth > 0 && EncounterController.Instance.Player.CurrentHealth <= 0)

{

playerDied = true;

}

// Set outcome UI

if (playerDied)

{

uiOutcome.SetOutcomeText(“You were defeated!”);

uiOutcome.SetButtonText(“Continue”);

}

else if (enemyDied)

{

uiOutcome.SetOutcomeText(“Victory!”);

uiOutcome.SetButtonText(“Continue”);

}

else

{

uiOutcome.SetOutcomeText(“You survived the encounter!”);

uiOutcome.SetButtonText(“Continue”);

}

// Play outcome animations

if (healthAnimationsOutcome.HasAnimations)

{

AnimationController.Instance.QueueHealthAnimations(healthAnimationsOutcome);

}

// Play the outcome animation which will trigger the outcome UI

AnimationController.Instance.PlayOutcomeAnimation();

}

private void OutcomeAnimationFinished()

{

Debug.Log(“Outcome animation finished”);

// Subscribe to the outcome button event

uiOutcome.OnOutcomeButtonPressed.AddListener(OutcomeButtonPressed);

// Show the outcome UI

uiOutcome.ShowOutcomePanel();

}

private void OutcomeButtonPressed()

{

Debug.Log(“Outcome button pressed”);

// Unsubscribe from UI events

uiOutcome.OnOutcomeButtonPressed.RemoveListener(OutcomeButtonPressed);

// Reset the encounter singleton flag since the encounter is completely finished

EncounterSingleton.Instance.IsEventCounterActive = false;

EncounterSingleton.Instance.CurrentTurn = 0;

// End the encounter and go back to map screen

EncounterController.Instance.EndEncounter();

StateController.Instance.TransitionToState(GameState.Map);

}

public override void OnStateEnding()

{

// Unsubscribe from animation events

AnimationController.Instance.AnimationEvents.OnOutcomeAnimationFinished.RemoveListener(OutcomeAnimationFinished);

AnimationController.Instance.AnimationEvents.OnProgressBarFinished.RemoveListener(ProgressBarFinished);

// Unsubscribe from UI events if they’re still active

if (uiEventCounter != null)

{

uiEventCounter.OnReadyButtonPressed.RemoveListener(ReadyButtonPressed);

}

if (uiOutcome != null)

{

uiOutcome.OnOutcomeButtonPressed.RemoveListener(OutcomeButtonPressed);

}

}

}

End File# Scripts/Battle/EncounterController.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.Events;

///

/// Manages the logical aspects of an encounter between the player and an enemy.

///

public class EncounterController : Singleton

{

[Header(“Prefabs”)]

[SerializeField] private GameObject playerPrefab;

[SerializeField] private GameObject enemyPrefab;

// References to the player and enemy entities

public EntityController Player { get; private set; }

public EntityController Enemy { get; private set; }

// Events

public UnityEvent OnEncounterStarted = new UnityEvent();

public UnityEvent OnEncounterEnded = new UnityEvent();

private EncounterData currentEncounter;

// Store references to all entities

private List entities = new List();

#region Unity Methods

protected override void Awake()

{

base.Awake();

// Ensure we have references to all entity controllers

SetupPlayer();

SetupEnemy();

}

#endregion

#region Encounter Setup and Control

///

/// Starts an encounter with the specified parameters.

///

public void StartEncounter()

{

currentEncounter = GameManager.Instance.CurrentEncounter;

if (currentEncounter == null)

{

Debug.LogError(“Cannot start encounter: no encounter data provided”);

return;

}

Debug.Log($“Starting encounter: {currentEncounter.EncounterName}”);

// Setup the player with current game state

PlayerData playerData = GameManager.Instance.PlayerData;

if (playerData != null)

{

Player.Initialize(playerData);

}

else

{

Debug.LogWarning(“No player data available, using default values”);

Player.Initialize(new PlayerData());

}

// Setup the enemy with data from the encounter

Enemy.Initialize(currentEncounter.Enemy);

// Gather all entities that will participate in the encounter

entities.Clear();

entities.Add(Player);

entities.Add(Enemy);

// Notify listeners that the encounter has started

OnEncounterStarted.Invoke();

}

///

/// Ends the current encounter and performs any cleanup.

///

public void EndEncounter()

{

Debug.Log(“Ending encounter”);

// Save any changes to player state if necessary

SavePlayerState();

// Notify listeners that the encounter has ended

OnEncounterEnded.Invoke();

}

///

/// Creates or retrieves the player entity controller.

///

private void SetupPlayer()

{

if (Player == null)

{

GameObject playerObj = Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);

Player = playerObj.GetComponent();

if (Player == null)

{

Debug.LogError(“PlayerController component missing from player prefab”);

}

}

}

///

/// Creates or retrieves the enemy entity controller.

///

private void SetupEnemy()

{

if (Enemy == null)

{

GameObject enemyObj = Instantiate(enemyPrefab, Vector3.zero, Quaternion.identity);

Enemy = enemyObj.GetComponent();

if (Enemy == null)

{

Debug.LogError(“EntityController component missing from enemy prefab”);

}

}

}

///

/// Saves the current player state at the end of the encounter.

///

private void SavePlayerState()

{

if (Player != null && GameManager.Instance != null)

{

// Save any changes to the player that should persist (like health)

PlayerData updatedPlayerData = new PlayerData(

Player.EntityName,

Player.MaxHealth,

Player.CurrentHealth

);

GameManager.Instance.UpdatePlayerData(updatedPlayerData);

}

}

#endregion

#region Effect Management

///

/// Returns effects that should be applied at the start of the encounter.

///

public List GetEncounterStartEffects()

{

List effects = new List();

if (currentEncounter != null && _currentEncounter.StartEffects != null)

{

effects.AddRange(currentEncounter.StartEffects);

}

return effects;

}

///

/// Returns effects that should be applied during each turn of the encounter.

///

public List GetOngoingEffects()

{

List effects = new List();

if (currentEncounter != null && _currentEncounter.OngoingEffects != null)

{

effects.AddRange(currentEncounter.OngoingEffects);

}

return effects;

}

///

/// Returns effects that should be applied at the end of the encounter.

///

public List GetEncounterOutcomeEffects()

{

List effects = new List();

if (currentEncounter != null && _currentEncounter.OutcomeEffects != null)

{

effects.AddRange(currentEncounter.OutcomeEffects);

}

return effects;

}

///

/// Applies a list of effects to the appropriate entities.

///

public void ApplyEffects(List effects)

{

foreach (EffectData effect in effects)

{

ApplyEffect(effect);

}

}

///

/// Applies a single effect to the appropriate entity.

///

private void ApplyEffect(EffectData effect)

{

switch (effect.EffectType)

{

case EffectType.PlayerHealth:

ApplyHealthEffect(Player, effect);

break;

case EffectType.EnemyHealth:

ApplyHealthEffect(Enemy, effect);

break;

default:

Debug.LogWarning($“Unhandled effect type: {effect.EffectType}”);

break;

}

}

///

/// Applies a health effect to the specified entity.

///

private void ApplyHealthEffect(EntityController entity, EffectData effect)

{

if (entity == null)

{

Debug.LogError(“Cannot apply health effect: entity is null”);

return;

}

int amount = effect.Value;

// For damage, we convert the positive value to negative

if (effect.IsHealthDecrease())

{

amount = -amount;

}

entity.ChangeHealth(amount);

}

#endregion

}

End File# Valentin-Butorin/MiniMap

Scripts/Data/EncounterData.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

///

/// Data structure for an encounter in the game.

///

[CreateAssetMenu(fileName = “New Encounter”, menuName = “Game Data/Encounter”)]

public class EncounterData : ScriptableObject

{

[Header(“Basic Info”)]

[Tooltip(“The name of this encounter”)]

public string EncounterName;

[Tooltip(“A short description of this encounter”)]

[TextArea(2, 5)]

public string Description;

[Header(“Enemy Info”)]

[Tooltip(“The enemy in this encounter”)]

public EnemyData Enemy;

[Header(“Encounter Settings”)]

[Tooltip(“The total number of turns in this encounter”)]

[Range(1, 10)]

public int TotalTurns = 3;

[Header(“Encounter Effects”)]

[Tooltip(“Effects that are applied at the start of the encounter”)]

public List StartEffects = new List();

[Tooltip(“Effects that are applied during each turn of the encounter”)]

public List OngoingEffects = new List();

[Tooltip(“Effects that are applied at the end of the encounter”)]

public List OutcomeEffects = new List();

[Header(“Rewards”)]

[Tooltip(“Health that is restored to the player after the encounter”)]

[Range(0, 100)]

public int HealthRestored = 0;

[Header(“Visuals”)]

[Tooltip(“The image used for this encounter in the UI”)]

public Sprite EncounterSprite;

}

///

/// Types of effects that can be applied during an encounter.

///

public enum EffectType

{

PlayerHealth,

EnemyHealth,

// Add other effect types as needed

}

///

/// Data for an effect that can be applied during an encounter.

///

[System.Serializable]

public class EffectData

{

[Tooltip(“The type of effect to apply”)]

public EffectType EffectType;

[Tooltip(“The value of the effect (e.g. amount of health added or removed)”)]

public int Value;

[Tooltip(“Optional description of what this effect represents in-game”)]

public string Description;

///

/// Helper method to determine if this effect decreases health.

///

public bool IsHealthDecrease()

{

return (EffectType == EffectType.PlayerHealth || EffectType == EffectType.EnemyHealth) && Value > 0;

}

///

/// Helper method to determine if this effect increases health.

///

public bool IsHealthIncrease()

{

return (EffectType == EffectType.PlayerHealth || EffectType == EffectType.EnemyHealth) && Value < 0;

}

}

End File# Scripts/Data/MapNodeData.cs

using System;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

///

/// Data structure for a node on the map.

///

[CreateAssetMenu(fileName = “New Map Node”, menuName = “Game Data/Map Node”)]

public class MapNodeData : ScriptableObject

{

[Header(“Node Information”)]

[Tooltip(“The unique identifier for this node”)]

public string NodeID;

[Tooltip(“The type of node”)]

public NodeType NodeType;

[Tooltip(“Human-readable name for this node”)]

public string NodeName;

[Tooltip(“Description of what happens at this node”)]

[TextArea(2, 5)]

public string Description;

[Header(“Node Connections”)]

[Tooltip(“IDs of nodes this node connects to”)]

public List ConnectedNodeIDs = new List();

[Header(“Node Coordinates”)]

[Tooltip(“X position on the map”)]

public float XPosition;

[Tooltip(“Y position on the map”)]

public float YPosition;

[Header(“Node Appearance”)]

[Tooltip(“Icon for the node on the map”)]

public Sprite NodeIcon;

[Header(“Encounter Data”)]

[Tooltip(“Data for an encounter that happens at this node (if applicable)”)]

public EncounterData Encounter;

[Header(“Special Node Properties”)]

[Tooltip(“Health restored at a rest node”)]

[Range(0, 100)]

public int RestNodeHealAmount = 20;

[Tooltip(“Whether this node has been visited”)]

public bool IsVisited = false;

///

/// Returns a unique key for this node based on its position.

///

public string GetPositionKey()

{

return $“{XPosition}{YPosition}”;

}

}

///

/// Types of nodes that can exist on the map.

///

public enum NodeType

{

Start, // Starting point

Enemy, // Combat encounter

Elite, // Harder combat encounter

Rest, // Rest area to heal

Event, // Random event

Boss, // Final boss encounter

Mystery // Unknown node type until visited

}

///

/// Extension methods for the NodeType enum.

///

public static class NodeTypeExtensions

{

///

/// Gets a color associated with the node type for UI representation.

///

public static Color GetColor(this NodeType nodeType)

{

switch (nodeType)

{

case NodeType.Start:

return Color.green;

case NodeType.Enemy:

return Color.red;

case NodeType.Elite:

return new Color(0.8f, 0.2f, 0.2f); // Darker red

case NodeType.Rest:

return Color.blue;

case NodeType.Event:

return Color.yellow;

case NodeType.Boss:

return new Color(0.5f, 0, 0.5f); // Purple

case NodeType.Mystery:

return Color.gray;

default:

return Color.white;

}

}

///

/// Gets a human-readable name for the node type.

///

public static string GetDisplayName(this NodeType nodeType)

{

switch (nodeType)

{

case NodeType.Start:

return “Başlangıç”;

case NodeType.Enemy:

return “Düşman”;

case NodeType.Elite:

return “Elit Düşman”;

case NodeType.Rest:

return “Dinlenme”;

case NodeType.Event:

return “Olay”;

case NodeType.Boss:

return “Şef”;

case NodeType.Mystery:

return “Gizemli”;

default:

return nodeType.ToString();

}

}

}

End File# Valentin-Butorin/MiniMap

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

///

/// Controls music and sound effects for the game.

///

public class AudioManager : Singleton

{

[Header(“Audio Sources”)]

[Tooltip(“Audio source for music”)]

[SerializeField] private AudioSource musicSource;

[Tooltip(“Audio source for sound effects”)]

[SerializeField] private AudioSource sfxSource;

[Header(“Audio Clips”)]

[Tooltip(“Main menu music”)]

[SerializeField] private AudioClip mainMenuMusic;

[Tooltip(“Map screen music”)]

[SerializeField] private AudioClip mapMusic;

[Tooltip(“Battle music”)]

[SerializeField] private AudioClip battleMusic;

[Tooltip(“Button click sound”)]

[SerializeField] private AudioClip buttonClickSound;

[Tooltip(“Node selection sound”)]

[SerializeField] private AudioClip nodeSelectSound;

[Tooltip(“Battle hit sound”)]

[SerializeField] private AudioClip hitSound;

[Tooltip(“Health gain sound”)]

[SerializeField] private AudioClip healSound;

[Tooltip(“Victory sound”)]

[SerializeField] private AudioClip victorySound;

[Tooltip(“Defeat sound”)]

[SerializeField] private AudioClip defeatSound;

[Header(“Volume Settings”)]

[Tooltip(“Master volume multiplier”)]

[Range(0, 1)]

[SerializeField] private float masterVolume = 1f;

[Tooltip(“Music volume multiplier”)]

[Range(0, 1)]

[SerializeField] private float musicVolume = 0.5f;

[Tooltip(“SFX volume multiplier”)]

[Range(0, 1)]

[SerializeField] private float sfxVolume = 0.7f;

[Tooltip(“How long the music crossfade takes”)]

[SerializeField] private float musicCrossfadeDuration = 1.5f;

// Keep track of what music is currently playing

private AudioClip currentMusic;

private Coroutine musicFadeCoroutine;

protected override void Awake()

{

base.Awake();

// Make sure audio sources are set up

if (musicSource == null)

{

GameObject musicObj = new GameObject(“Music Source”);

musicObj.transform.parent = transform;

musicSource = musicObj.AddComponent();

musicSource.loop = true;

}

if (sfxSource == null)

{

GameObject sfxObj = new GameObject(“SFX Source”);

sfxObj.transform.parent = transform;

sfxSource = sfxObj.AddComponent();

}

// Initialize volume

UpdateVolume();

}

void Start()

{

// Subscribe to state change events

StateController.Instance.OnStateChanged.AddListener(HandleStateChanged);

}

void OnDestroy()

{

// Unsubscribe from state change events

if (StateController.Instance != null)

{

StateController.Instance.OnStateChanged.RemoveListener(HandleStateChanged);

}

}

///

/// Handles state changes to play appropriate music.

///

private void HandleStateChanged(GameState newState)

{

switch (newState)

{

case GameState.MainMenu:

PlayMusic(mainMenuMusic);

break;

case GameState.Map:

PlayMusic(mapMusic);

break;

case GameState.Battle:

PlayMusic(battleMusic);

break;

}

}

///

/// Play a sound effect.

///

public void PlaySFX(AudioClip clip)

{

if (clip != null)

{

sfxSource.PlayOneShot(clip, _sfxVolume masterVolume);

}

}

///

/// Play the button click sound.

///

public void PlayButtonClick()

{

PlaySFX(buttonClickSound);

}

///

/// Play the node selection sound.

///

public void PlayNodeSelect()

{

PlaySFX(nodeSelectSound);

}

///

/// Play the hit sound.

///

public void PlayHitSound()

{

PlaySFX(hitSound);

}

///

/// Play the heal sound.

///

public void PlayHealSound()

{

PlaySFX(healSound);

}

///

/// Play the victory sound.

///

public void PlayVictorySound()

{

PlaySFX(victorySound);

}

///

/// Play the defeat sound.

///

public void PlayDefeatSound()

{

PlaySFX(defeatSound);

}

///

/// Play music with a smooth crossfade transition.

///

public void PlayMusic(AudioClip music)

{

// Don’t switch if it’s already the current music

if (currentMusic == music)

return;

currentMusic = music;

// If a fade is in progress, stop it

if (musicFadeCoroutine != null)

{

StopCoroutine(musicFadeCoroutine);

}

// If the music source is already playing, fade it out and then in with new music

if (musicSource.isPlaying)

{

musicFadeCoroutine = StartCoroutine(CrossfadeMusic(music));

}

else

{

// If no music is playing, just start the new music

musicSource.clip = music;

musicSource.volume = _musicVolume masterVolume;

musicSource.Play();

}

}

///

/// Coroutine for

Edited 16 files+1975-1808

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.