Implement Fort Fight minigame (#75)
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #75
This commit is contained in:
55
Assets/Scripts/Minigames/FortFight/Data/FortFightEnums.cs
Normal file
55
Assets/Scripts/Minigames/FortFight/Data/FortFightEnums.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
namespace Minigames.FortFight.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Game mode for Fort Fight minigame
|
||||
/// </summary>
|
||||
public enum FortFightGameMode
|
||||
{
|
||||
SinglePlayer, // Player vs AI
|
||||
TwoPlayer // Player vs Player
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current turn state in the game
|
||||
/// </summary>
|
||||
public enum TurnState
|
||||
{
|
||||
PlayerOneTurn,
|
||||
PlayerTwoTurn,
|
||||
AITurn,
|
||||
TransitioningTurn, // Transitioning between turns (projectile in flight, waiting for settle)
|
||||
GameOver
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Material types for fort blocks
|
||||
/// </summary>
|
||||
public enum BlockMaterial
|
||||
{
|
||||
Cardboard,
|
||||
Metal,
|
||||
Glass
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Size categories for fort blocks
|
||||
/// </summary>
|
||||
public enum BlockSize
|
||||
{
|
||||
Small,
|
||||
Medium,
|
||||
Large
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of projectiles available
|
||||
/// </summary>
|
||||
public enum ProjectileType
|
||||
{
|
||||
Toaster, // Standard physics projectile
|
||||
Vacuum, // Heavy, rolls on floor
|
||||
CeilingFan, // Drops straight down
|
||||
TrashBag // Explodes on impact
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9891698193c757344bc2f3f26730248a
|
||||
156
Assets/Scripts/Minigames/FortFight/Data/PlayerAmmoState.cs
Normal file
156
Assets/Scripts/Minigames/FortFight/Data/PlayerAmmoState.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Minigames.FortFight.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates all ammunition state for a single player.
|
||||
/// Tracks cooldowns, selection, and usage history per player.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PlayerAmmoState
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public int PlayerIndex { get; private set; }
|
||||
public ProjectileType SelectedAmmo { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region State
|
||||
|
||||
// Cooldowns per projectile type (turns remaining)
|
||||
private Dictionary<ProjectileType, int> cooldowns;
|
||||
|
||||
// Optional: Track usage for statistics/analytics
|
||||
private Dictionary<ProjectileType, int> usageCount;
|
||||
private ProjectileType lastUsedProjectile;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PlayerAmmoState(int playerIndex, ProjectileType defaultAmmo)
|
||||
{
|
||||
PlayerIndex = playerIndex;
|
||||
SelectedAmmo = defaultAmmo;
|
||||
cooldowns = new Dictionary<ProjectileType, int>();
|
||||
usageCount = new Dictionary<ProjectileType, int>();
|
||||
lastUsedProjectile = defaultAmmo;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cooldown Management
|
||||
|
||||
/// <summary>
|
||||
/// Initialize cooldown for a specific projectile type.
|
||||
/// </summary>
|
||||
public void InitializeCooldown(ProjectileType type)
|
||||
{
|
||||
if (!cooldowns.ContainsKey(type))
|
||||
{
|
||||
cooldowns[type] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set cooldown for a specific projectile type.
|
||||
/// </summary>
|
||||
public void SetCooldown(ProjectileType type, int turns)
|
||||
{
|
||||
cooldowns[type] = turns;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get remaining cooldown turns for a projectile type.
|
||||
/// </summary>
|
||||
public int GetCooldown(ProjectileType type)
|
||||
{
|
||||
return cooldowns.ContainsKey(type) ? cooldowns[type] : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if projectile type is available (not on cooldown).
|
||||
/// </summary>
|
||||
public bool IsAmmoAvailable(ProjectileType type)
|
||||
{
|
||||
return GetCooldown(type) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrement all cooldowns by 1 turn.
|
||||
/// Returns list of projectile types that completed cooldown this turn.
|
||||
/// </summary>
|
||||
public List<ProjectileType> DecrementCooldowns()
|
||||
{
|
||||
List<ProjectileType> completedCooldowns = new List<ProjectileType>();
|
||||
List<ProjectileType> types = new List<ProjectileType>(cooldowns.Keys);
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (cooldowns[type] > 0)
|
||||
{
|
||||
cooldowns[type]--;
|
||||
|
||||
if (cooldowns[type] == 0)
|
||||
{
|
||||
completedCooldowns.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return completedCooldowns;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Usage Tracking
|
||||
|
||||
/// <summary>
|
||||
/// Record that a projectile type was used.
|
||||
/// </summary>
|
||||
public void RecordUsage(ProjectileType type)
|
||||
{
|
||||
lastUsedProjectile = type;
|
||||
|
||||
if (!usageCount.ContainsKey(type))
|
||||
{
|
||||
usageCount[type] = 0;
|
||||
}
|
||||
usageCount[type]++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get usage count for a projectile type.
|
||||
/// </summary>
|
||||
public int GetUsageCount(ProjectileType type)
|
||||
{
|
||||
return usageCount.ContainsKey(type) ? usageCount[type] : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the last projectile type used by this player.
|
||||
/// </summary>
|
||||
public ProjectileType LastUsedProjectile => lastUsedProjectile;
|
||||
|
||||
/// <summary>
|
||||
/// Get total number of projectiles used by this player.
|
||||
/// </summary>
|
||||
public int TotalUsageCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int total = 0;
|
||||
foreach (var count in usageCount.Values)
|
||||
{
|
||||
total += count;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd7545bfc92d4096b53954bab9884b15
|
||||
timeCreated: 1764797211
|
||||
23
Assets/Scripts/Minigames/FortFight/Data/PlayerData.cs
Normal file
23
Assets/Scripts/Minigames/FortFight/Data/PlayerData.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Minigames.FortFight.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a player in the Fort Fight minigame
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PlayerData
|
||||
{
|
||||
public string PlayerName;
|
||||
public bool IsAI;
|
||||
public int PlayerIndex; // 0 for Player One, 1 for Player Two/AI
|
||||
|
||||
public PlayerData(string name, bool isAI, int playerIndex)
|
||||
{
|
||||
PlayerName = name;
|
||||
IsAI = isAI;
|
||||
PlayerIndex = playerIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f310a90c43a9b3049b875c84f2d9043a
|
||||
94
Assets/Scripts/Minigames/FortFight/Data/ProjectileConfig.cs
Normal file
94
Assets/Scripts/Minigames/FortFight/Data/ProjectileConfig.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.FortFight.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration data for a projectile type.
|
||||
/// Stored centrally in FortFightSettings instead of individual ScriptableObject assets.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ProjectileConfig
|
||||
{
|
||||
[Header("Identity")]
|
||||
[Tooltip("Type of projectile this config represents")]
|
||||
public ProjectileType projectileType;
|
||||
|
||||
[Tooltip("Unique string identifier (auto-generated from type)")]
|
||||
public string projectileId;
|
||||
|
||||
[Header("Prefab")]
|
||||
[Tooltip("Prefab for this projectile (should have ProjectileBase component)")]
|
||||
public GameObject prefab;
|
||||
|
||||
[Header("Ammunition System")]
|
||||
[Tooltip("Cooldown in turns after use")]
|
||||
public int cooldownTurns = 2;
|
||||
|
||||
[Header("UI")]
|
||||
[Tooltip("Icon sprite for ammunition UI")]
|
||||
public Sprite icon;
|
||||
|
||||
[Tooltip("Display name for this projectile type")]
|
||||
public string displayName;
|
||||
|
||||
[Tooltip("Description of projectile behavior")]
|
||||
[TextArea(2, 4)]
|
||||
public string description;
|
||||
|
||||
[Header("Combat Stats")]
|
||||
[Tooltip("Damage dealt on impact")]
|
||||
public float damage = 20f;
|
||||
|
||||
[Header("Physics")]
|
||||
[Tooltip("Mass for physics simulation (affects trajectory and force)")]
|
||||
public float mass = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Get the ProjectileBase component from the prefab
|
||||
/// </summary>
|
||||
public Projectiles.ProjectileBase GetProjectileComponent()
|
||||
{
|
||||
if (prefab == null) return null;
|
||||
return prefab.GetComponent<Projectiles.ProjectileBase>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get damage value from config
|
||||
/// </summary>
|
||||
public float GetDamage()
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get mass value from config
|
||||
/// </summary>
|
||||
public float GetMass()
|
||||
{
|
||||
return mass;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate and auto-generate projectileId from type
|
||||
/// </summary>
|
||||
public void Validate()
|
||||
{
|
||||
if (string.IsNullOrEmpty(projectileId))
|
||||
{
|
||||
projectileId = GenerateIdFromType(projectileType);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
displayName = projectileType.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateIdFromType(ProjectileType type)
|
||||
{
|
||||
return type.ToString().ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d60235e77c7456380c10f9c145750bf
|
||||
timeCreated: 1764778577
|
||||
Reference in New Issue
Block a user