changes
@@ -1,61 +1,61 @@
|
||||
@inject IGameDataLoader DataLoader
|
||||
@inject IBattleEngine BattleEngine
|
||||
@inject ILocalStorageService Storage
|
||||
@inject NavigationManager Nav
|
||||
|
||||
<div class="battle-arena-wrapper" tabindex="0" @ref="arenaElement" @onkeydown="HandleKeyDown" autofocus>
|
||||
<!-- Top Header / Bar -->
|
||||
<div class="battle-arena-wrapper" tabindex="0" @onkeydown="HandleKeyDown" @ref="arenaElement">
|
||||
<!-- Top HUD / Level Info -->
|
||||
<div class="battle-header">
|
||||
|
||||
<button class="btn-back" @onclick="GoBackToMap">⬅ Mapa</button>
|
||||
<div class="level-info">
|
||||
<span class="world-title">@CurrentLevel.Name</span>
|
||||
@if (CurrentLevel.IsBoss)
|
||||
{
|
||||
<span class="boss-badge">👑 BOSS</span>
|
||||
<span class="boss-badge">👑 BOSS SÚBOJ</span>
|
||||
}
|
||||
</div>
|
||||
<div class="combo-counter @(State.ComboStreak > 1 ? "active-streak" : "")">
|
||||
🔥 Kombo: <strong>@State.ComboStreak</strong>
|
||||
🔥 Séria: <strong>@State.ComboStreak</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Feedback / Toast Banner -->
|
||||
@if (!string.IsNullOrEmpty(State.LastFeedbackMessage))
|
||||
<!-- Dynamic Feedback Banner -->
|
||||
@if (!string.IsNullOrEmpty(State.LastFeedbackMessage) && !State.IsBattleOver)
|
||||
{
|
||||
<div class="feedback-banner @GetFeedbackClass()">
|
||||
<div class="feedback-banner @GetFeedbackClass() anim-fade-in">
|
||||
@State.LastFeedbackMessage
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Main Combat Arena -->
|
||||
<div class="arena-stage" style="background: linear-gradient(rgba(0,0,0,0.15), rgba(0,0,0,0.35)), url('assets/images/backgrounds/world1_meadow.jpg') center/cover no-repeat;">
|
||||
<!-- Player Side -->
|
||||
|
||||
<div class="combatant player-side @GetPlayerAnimationClass()">
|
||||
<!-- Visual Combat Stage with Dynamic World Background -->
|
||||
<div class="arena-stage" style="background: linear-gradient(rgba(0,0,0,0.35), rgba(0,0,0,0.45)), url('@BackgroundImage') center/cover no-repeat;">
|
||||
<!-- Hero Side -->
|
||||
<div class="combatant hero-side @GetPlayerAnimationClass()">
|
||||
<div class="combatant-info">
|
||||
<span class="combatant-name">@Hero.Name</span>
|
||||
<div class="hp-hearts">
|
||||
@for (int i = 1; i <= State.PlayerMaxHp; i++)
|
||||
@for (int i = 0; i < State.PlayerMaxHp; i++)
|
||||
{
|
||||
<span class="heart @(i <= State.PlayerCurrentHp ? "full" : "empty")">
|
||||
@(i <= State.PlayerCurrentHp ? "❤️" : "🤍")
|
||||
</span>
|
||||
if (i < State.PlayerCurrentHp)
|
||||
{
|
||||
<span class="heart full">❤️</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="heart empty">🖤</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Visual (4 Phases & Combat Poses) -->
|
||||
<!-- Hero Visual (4 Phases & Combat Poses) -->
|
||||
<div class="character-sprite-box">
|
||||
<div class="sprite-phase-indicator">Fáza @State.PlayerHpPhase / 4</div>
|
||||
<img src="@GetCharacterImage(Hero.AssetFolder, State.PlayerHpPhase, State.PlayerPose)"
|
||||
alt="@Hero.Name"
|
||||
class="character-image"
|
||||
onerror="this.src='data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'180\' height=\'240\'><rect width=\'100%\' height=\'100%\' fill=\'%234a90e2\'/><text x=\'50%\' y=\'50%\' fill=\'white\' font-size=\'20\' text-anchor=\'middle\'>🧙♂️ @Hero.Name (Fáza @State.PlayerHpPhase)</text></svg>'"/>
|
||||
class="character-image hero-img" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VS Divider / Dynamic Timer -->
|
||||
<div class="arena-center">
|
||||
<!-- Center Round Timer Orb -->
|
||||
<div class="arena-center-timer">
|
||||
<div class="timer-orb @GetTimerColorClass()">
|
||||
<div class="timer-seconds">@RemainingTimeSeconds.ToString("F1")s</div>
|
||||
<div class="timer-label">@(State.IsDefensePhase ? "OBRANA!" : "ÚTOK")</div>
|
||||
@@ -77,8 +77,7 @@
|
||||
<div class="sprite-phase-indicator">Fáza @State.EnemyHpPhase / 4</div>
|
||||
<img src="@GetCharacterImage(State.Enemy.AssetFolder, State.EnemyHpPhase, State.EnemyPose)"
|
||||
alt="@State.Enemy.Name"
|
||||
class="character-image enemy-img"
|
||||
onerror="this.src='data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'180\' height=\'240\'><rect width=\'100%\' height=\'100%\' fill=\'%23e74c3c\'/><text x=\'50%\' y=\'50%\' fill=\'white\' font-size=\'20\' text-anchor=\'middle\'>👾 @State.Enemy.Name (Fáza @State.EnemyHpPhase)</text></svg>'"/>
|
||||
class="character-image enemy-img" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,39 +104,116 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
</div>
|
||||
|
||||
<!-- FULLSCREEN VICTORY / DEFEAT CELEBRATION OVERLAY -->
|
||||
@if (State.IsBattleOver)
|
||||
{
|
||||
<!-- Victory / Defeat Modal -->
|
||||
<div class="battle-end-card @(State.IsVictory ? "victory-card" : "defeat-card")">
|
||||
<h2>@(State.IsVictory ? "🏆 VÍŤAZSTVO!" : "💀 PORÁŽKA!")</h2>
|
||||
<p>@State.LastFeedbackMessage</p>
|
||||
<div class="end-actions">
|
||||
<div class="battle-end-overlay anim-fade-in">
|
||||
<div class="celebration-modal @(State.IsVictory ? "victory-theme" : "defeat-theme") anim-victory-modal-pop">
|
||||
@if (State.IsVictory)
|
||||
{
|
||||
<button class="action-btn next-level-btn" @onclick="OnVictoryContinue">Pokračovať v ceste ➡️</button>
|
||||
<div class="celebration-particles">
|
||||
<span class="particle star-p1">✨</span>
|
||||
<span class="particle star-p2">⭐</span>
|
||||
<span class="particle star-p3">🌟</span>
|
||||
<span class="particle star-p4">✨</span>
|
||||
</div>
|
||||
|
||||
<div class="celebration-header">
|
||||
<span class="celebration-crown">👑</span>
|
||||
<h1 class="celebration-title">LEVEL PREKONANÝ!</h1>
|
||||
<p class="celebration-subtitle">Úspešne si vyriešil všetky úlohy a zvíťazil!</p>
|
||||
</div>
|
||||
|
||||
<div class="celebration-body">
|
||||
<div class="celebration-hero-stage">
|
||||
<img src="@GetCharacterImage(Hero.AssetFolder, 1, CombatPose.Attack)"
|
||||
alt="@Hero.Name"
|
||||
class="celebration-hero-img anim-hero-victory" />
|
||||
<span class="victory-hero-name">@Hero.Name</span>
|
||||
</div>
|
||||
|
||||
<div class="celebration-rewards-card">
|
||||
<div class="reward-row">
|
||||
<span class="reward-icon">⭐</span>
|
||||
<div class="reward-info">
|
||||
<strong>@(CurrentLevel.IsBoss ? "+3 HVIEZDY" : "+1 HVIEZDA")</strong>
|
||||
<span>Odmena za víťazstvo</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reward-row">
|
||||
<span class="reward-icon">💰</span>
|
||||
<div class="reward-info">
|
||||
<strong>@(CurrentLevel.IsBoss ? "+50 ZLATA" : "+20 ZLATA")</strong>
|
||||
<span>Kráľovská odmena</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="celebration-actions">
|
||||
@if (NextLevel != null)
|
||||
{
|
||||
<button class="btn-grand-celebration btn-next-quest" @onclick="HandleNextLevelClick">
|
||||
🚀 POSTÚPIŤ DO LEVELU: @NextLevel.Name ➜
|
||||
</button>
|
||||
}
|
||||
<div class="secondary-actions-row">
|
||||
<button class="btn-secondary-celebration" @onclick="OnVictoryContinue">
|
||||
🗺️ Mapa sveta
|
||||
</button>
|
||||
<button class="btn-secondary-celebration" @onclick="RetryBattle">
|
||||
🔁 Hrať znova
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="action-btn retry-btn" @onclick="RetryBattle">Skúsiť znova 🔄</button>
|
||||
<div class="defeat-header">
|
||||
<span class="defeat-icon">💀</span>
|
||||
<h1 class="defeat-title">NEVZDÁVAJ SA!</h1>
|
||||
<p class="defeat-subtitle">@State.LastFeedbackMessage</p>
|
||||
</div>
|
||||
|
||||
<div class="defeat-body">
|
||||
<p class="defeat-encouragement">
|
||||
„Každý udatný počtár sa učí na vlastných chybách. Skús to znova a ukáž svoju matematickú silu!“
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="celebration-actions">
|
||||
<button class="btn-grand-celebration btn-retry-quest" @onclick="RetryBattle">
|
||||
🔄 SKÚSIŤ ZNOVA ⚔️
|
||||
</button>
|
||||
<button class="btn-secondary-celebration" @onclick="GoBackToMap">
|
||||
🗺️ Návrat na mapu
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public Hero Hero { get; set; } = new();
|
||||
[Parameter] public Level CurrentLevel { get; set; } = new();
|
||||
[Parameter] public int PlayerGrade { get; set; } = 1;
|
||||
[Parameter] public string BackgroundImage { get; set; } = "assets/images/backgrounds/world1_meadow.jpg";
|
||||
[Parameter] public GameConfig Config { get; set; } = new();
|
||||
[Parameter] public EventCallback OnReturnToMap { get; set; }
|
||||
[Parameter] public EventCallback<Level> OnLevelCompleted { get; set; }
|
||||
[Parameter] public EventCallback<Level> OnNextLevelRequested { get; set; }
|
||||
|
||||
private BattleState State => BattleEngine.State;
|
||||
private string CurrentInput { get; set; } = string.Empty;
|
||||
private System.Threading.Timer? _timer;
|
||||
private double RemainingTimeSeconds { get; set; } = 6.0;
|
||||
|
||||
private Level? NextLevel => DataLoader.GetNextLevel(PlayerGrade, CurrentLevel.Id);
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
StartBattle();
|
||||
@@ -229,6 +305,18 @@
|
||||
await OnLevelCompleted.InvokeAsync(CurrentLevel);
|
||||
}
|
||||
|
||||
private async Task HandleNextLevelClick()
|
||||
{
|
||||
if (NextLevel != null)
|
||||
{
|
||||
await OnNextLevelRequested.InvokeAsync(NextLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
await OnVictoryContinue();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GoBackToMap()
|
||||
{
|
||||
_timer?.Dispose();
|
||||
@@ -297,23 +385,28 @@
|
||||
if (e.Key == "Enter")
|
||||
{
|
||||
if (State.IsVictory)
|
||||
await OnVictoryContinue();
|
||||
{
|
||||
if (NextLevel != null)
|
||||
await HandleNextLevelClick();
|
||||
else
|
||||
await OnVictoryContinue();
|
||||
}
|
||||
else
|
||||
{
|
||||
await RetryBattle();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (State.CurrentProblem.InputType == "MultipleChoice" || State.IsDefensePhase)
|
||||
{
|
||||
// Handle number keys 1, 2, 3 to pick choices
|
||||
if (int.TryParse(e.Key, out int choiceIndex) && choiceIndex >= 1 && choiceIndex <= State.CurrentProblem.Choices.Count)
|
||||
{
|
||||
await HandleChoiceSelected(State.CurrentProblem.Choices[choiceIndex - 1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle A/N shortcuts for ÁNO / NIE
|
||||
if (e.Key.Equals("a", StringComparison.OrdinalIgnoreCase) || e.Key.Equals("y", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var match = State.CurrentProblem.Choices.FirstOrDefault(c => c.StartsWith("Á", StringComparison.OrdinalIgnoreCase) || c.StartsWith("A", StringComparison.OrdinalIgnoreCase));
|
||||
@@ -329,7 +422,6 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
// Direct numeric input (0-9, Backspace, Enter)
|
||||
if (e.Key.Length == 1 && char.IsDigit(e.Key[0]))
|
||||
{
|
||||
if (CurrentInput.Length < 6)
|
||||
@@ -356,4 +448,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,106 +1,379 @@
|
||||
@inject IGameDataLoader DataLoader
|
||||
@inject ILocalStorageService Storage
|
||||
|
||||
<div class="character-select-screen">
|
||||
<div class="parchment-container select-card-compact">
|
||||
<div class="select-header">
|
||||
<h1 class="game-main-title">🏰 ČÍSELNÁ VÝPRAVA</h1>
|
||||
<p class="subtitle">Vytvor si svojho hrdinu a vyber ročník</p>
|
||||
<div class="wizard-screen">
|
||||
@switch (CurrentStep)
|
||||
{
|
||||
case WizardStep.SelectGrade:
|
||||
{
|
||||
<div class="parchment-container wizard-container">
|
||||
<div class="wizard-top-bar">
|
||||
<button class="btn-wizard-back" @onclick="HandleBackToMenu">
|
||||
⬅ Späť do menu
|
||||
</button>
|
||||
<div class="wizard-stepper">
|
||||
<span class="step-badge active">1. Ročník 🎒</span>
|
||||
<span class="step-divider">➔</span>
|
||||
<span class="step-badge">2. Hrdina 🛡️</span>
|
||||
<span class="step-divider">➔</span>
|
||||
<span class="step-badge">3. Meno 👑</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-content-grid">
|
||||
<!-- LEFT: ROČNÍK & MENO -->
|
||||
<div class="select-col-left">
|
||||
<div class="selection-section">
|
||||
<h2 class="step-title">1. Tvoj ročník</h2>
|
||||
<div class="grade-toggle-group">
|
||||
<button class="grade-btn @(SelectedGrade == 1 ? "active" : "")" @onclick="() => SetGrade(1)">
|
||||
<span class="grade-badge">🎒 1. ROČNÍK</span>
|
||||
<span class="grade-desc">Do 10 / 20</span>
|
||||
</button>
|
||||
<button class="grade-btn @(SelectedGrade == 2 ? "active" : "")" @onclick="() => SetGrade(2)">
|
||||
<span class="grade-badge">🎒 2. ROČNÍK</span>
|
||||
<span class="grade-desc">Do 20 / 100</span>
|
||||
</button>
|
||||
<button class="grade-btn @(SelectedGrade == 3 ? "active" : "")" @onclick="() => SetGrade(3)">
|
||||
<span class="grade-badge">🎒 3. ROČNÍK</span>
|
||||
<span class="grade-desc">Násobilka & delenie</span>
|
||||
<div class="wizard-header">
|
||||
<h1 class="wizard-title">🎒 VYBER SI ROČNÍK</h1>
|
||||
<p class="wizard-subtitle">Zvoľ si úroveň matematických výziev pre svoje dobrodružstvo</p>
|
||||
</div>
|
||||
|
||||
<div class="grades-grid">
|
||||
<!-- GRADE 1 -->
|
||||
<div class="grade-card grade-1-card @(SelectedGrade == 1 ? "selected" : "")" @onclick="() => SelectGradeAndProceed(1)">
|
||||
<div class="grade-banner-stage" style="background: url('assets/images/backgrounds/world1_meadow.jpg') center/cover no-repeat;">
|
||||
<div class="grade-banner-overlay">
|
||||
<span class="grade-card-icon">⭐</span>
|
||||
<div class="grade-card-badge grade-1-badge">1. ROČNÍK</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grade-card-content">
|
||||
<h3 class="grade-card-title">Prváčik</h3>
|
||||
<p class="grade-card-desc">Základné sčítanie a odčítanie v rozprávkovej lúke.</p>
|
||||
<ul class="grade-topics-list">
|
||||
<li>➕ Sčítanie a odčítanie do 10 a 20</li>
|
||||
<li>⚖️ Porovnávanie čísel (<, >, =)</li>
|
||||
<li>🔟 Počítanie po desiatkach do 100</li>
|
||||
</ul>
|
||||
<button class="btn-grade-select btn-grade-1" @onclick:stopPropagation="true" @onclick="() => SelectGradeAndProceed(1)">
|
||||
Zvoliť 1. ročník ➜
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="selection-section">
|
||||
<h2 class="step-title">3. Meno hrdinu</h2>
|
||||
<div class="name-field-row">
|
||||
<input type="text" class="hero-name-input" @bind="HeroName" placeholder="Tvoje meno..." maxlength="20" />
|
||||
<button class="btn-start-quest" @onclick="StartQuest">
|
||||
Vstúpiť do hry 🚀
|
||||
<!-- GRADE 2 -->
|
||||
<div class="grade-card grade-2-card @(SelectedGrade == 2 ? "selected" : "")" @onclick="() => SelectGradeAndProceed(2)">
|
||||
<div class="grade-banner-stage" style="background: url('assets/images/backgrounds/world2_forest.jpg') center/cover no-repeat;">
|
||||
<div class="grade-banner-overlay">
|
||||
<span class="grade-card-icon">🌟</span>
|
||||
<div class="grade-card-badge grade-2-badge">2. ROČNÍK</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grade-card-content">
|
||||
<h3 class="grade-card-title">Druhák</h3>
|
||||
<p class="grade-card-desc">Počítanie do 100 s prechodom a úvod do násobilky.</p>
|
||||
<ul class="grade-topics-list">
|
||||
<li>➕ Sčítanie a odčítanie do 100 s prechodom</li>
|
||||
<li>⚖️ Porovnávanie hodnôt do 100</li>
|
||||
<li>✖️ Malá násobilka (2, 3, 5, 10)</li>
|
||||
</ul>
|
||||
<button class="btn-grade-select btn-grade-2" @onclick:stopPropagation="true" @onclick="() => SelectGradeAndProceed(2)">
|
||||
Zvoliť 2. ročník ➜
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- GRADE 3 -->
|
||||
<div class="grade-card grade-3-card @(SelectedGrade == 3 ? "selected" : "")" @onclick="() => SelectGradeAndProceed(3)">
|
||||
<div class="grade-banner-stage" style="background: url('assets/images/backgrounds/world3_river.jpg') center/cover no-repeat;">
|
||||
<div class="grade-banner-overlay">
|
||||
<span class="grade-card-icon">👑</span>
|
||||
<div class="grade-card-badge grade-3-badge">3. ROČNÍK</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grade-card-content">
|
||||
<h3 class="grade-card-title">Tretiak</h3>
|
||||
<p class="grade-card-desc">Kompletná násobilka, delenie a počítanie do tisícky!</p>
|
||||
<ul class="grade-topics-list">
|
||||
<li>✖️ Celá násobilka a delenie (2 – 10)</li>
|
||||
<li>🧮 Počítanie do 1000 (stovky a desiatky)</li>
|
||||
<li>🏆 Finálne bitky o kráľovskú citadelu</li>
|
||||
</ul>
|
||||
<button class="btn-grade-select btn-grade-3" @onclick:stopPropagation="true" @onclick="() => SelectGradeAndProceed(3)">
|
||||
Zvoliť 3. ročník ➜
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
break;
|
||||
}
|
||||
|
||||
<!-- RIGHT: VÝBER HRDINU -->
|
||||
<div class="select-col-right">
|
||||
<div class="selection-section">
|
||||
<h2 class="step-title">2. Vyber si hrdinu</h2>
|
||||
<div class="heroes-grid">
|
||||
case WizardStep.SelectHero:
|
||||
{
|
||||
<div class="parchment-container wizard-container">
|
||||
<div class="wizard-top-bar">
|
||||
<button class="btn-wizard-back" @onclick="() => CurrentStep = WizardStep.SelectGrade">
|
||||
⬅ Späť na ročník
|
||||
</button>
|
||||
<div class="wizard-stepper">
|
||||
<span class="step-badge completed" @onclick="() => CurrentStep = WizardStep.SelectGrade">✓ @SelectedGrade. Ročník</span>
|
||||
<span class="step-divider">➔</span>
|
||||
<span class="step-badge active">2. Hrdina 🛡️</span>
|
||||
<span class="step-divider">➔</span>
|
||||
<span class="step-badge">3. Meno 👑</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-header">
|
||||
<h1 class="wizard-title">🛡️ ZVOĽ SI SVOJHO HRDINU</h1>
|
||||
<p class="wizard-subtitle">Vyber si postavu, s ktorou zachrániš Číselné Kráľovstvo</p>
|
||||
</div>
|
||||
|
||||
<div class="hero-showcase-grid">
|
||||
@foreach (var hero in DataLoader.Heroes)
|
||||
{
|
||||
<div class="hero-card @(SelectedHeroId == hero.Id ? "selected-card" : "")"
|
||||
@onclick="() => SelectHero(hero.Id)">
|
||||
<div class="hero-avatar">
|
||||
@(hero.Id == "knight" ? "⚔️" : hero.Id == "mage" ? "🧙♂️" : "🏹")
|
||||
var isSelected = SelectedHeroId == hero.Id;
|
||||
var heroImg = $"{hero.AssetFolder}_idle_p1.png";
|
||||
var themeClass = hero.Id switch
|
||||
{
|
||||
"knight" => "hero-theme-knight",
|
||||
"mage" => "hero-theme-mage",
|
||||
"archer" => "hero-theme-archer",
|
||||
_ => "hero-theme-knight"
|
||||
};
|
||||
var icon = hero.Id switch
|
||||
{
|
||||
"knight" => "⚔️",
|
||||
"mage" => "🔮",
|
||||
"archer" => "🏹",
|
||||
_ => "🛡️"
|
||||
};
|
||||
|
||||
<div class="hero-showcase-card @themeClass @(isSelected ? "selected" : "")"
|
||||
@onclick="() => SelectHeroAndProceed(hero.Id)">
|
||||
<div class="hero-card-banner">
|
||||
<span class="hero-crest-icon">@icon</span>
|
||||
<span class="hero-class-label">@hero.Title</span>
|
||||
</div>
|
||||
<h3 class="hero-name">@hero.Name</h3>
|
||||
<span class="hero-title">@hero.Title</span>
|
||||
<div class="hero-skill">
|
||||
✨ @hero.SpecialAttackName
|
||||
|
||||
<div class="hero-portrait-stage">
|
||||
<img src="@heroImg" alt="@hero.Name" class="hero-portrait-img anim-hero-idle" />
|
||||
</div>
|
||||
|
||||
<div class="hero-info-box">
|
||||
<h3 class="hero-title-name">@hero.Name</h3>
|
||||
<p class="hero-lore-desc">@hero.Description</p>
|
||||
|
||||
<div class="hero-skill-pill">
|
||||
✨ <strong>@hero.SpecialAttackName</strong>
|
||||
</div>
|
||||
|
||||
<div class="hero-stats-row">
|
||||
<span class="stat-tag">❤️ @hero.BaseHp HP</span>
|
||||
<span class="stat-tag">⚡ @hero.AttackPower ÚTOK</span>
|
||||
<span class="stat-tag">🛡️ ŠTÍT</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn-hero-select" @onclick:stopPropagation="true" @onclick="() => SelectHeroAndProceed(hero.Id)">
|
||||
Zvoliť hrdinu ➜
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
break;
|
||||
}
|
||||
|
||||
case WizardStep.NameAndStart:
|
||||
{
|
||||
<div class="parchment-container wizard-container wizard-name-container">
|
||||
<div class="wizard-top-bar">
|
||||
<button class="btn-wizard-back" @onclick="() => CurrentStep = WizardStep.SelectHero">
|
||||
⬅ Späť na výber hrdinu
|
||||
</button>
|
||||
<div class="wizard-stepper">
|
||||
<span class="step-badge completed" @onclick="() => CurrentStep = WizardStep.SelectGrade">✓ @SelectedGrade. Ročník</span>
|
||||
<span class="step-divider">➔</span>
|
||||
<span class="step-badge completed" @onclick="() => CurrentStep = WizardStep.SelectHero">✓ @CurrentSelectedHero.Name</span>
|
||||
<span class="step-divider">➔</span>
|
||||
<span class="step-badge active">3. Meno & Štart 👑</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-header">
|
||||
<h1 class="wizard-title">👑 POJMENUJ SVOJHO HRDINU</h1>
|
||||
<p class="wizard-subtitle">Posledný krok pred otvorením brány kráľovstva!</p>
|
||||
</div>
|
||||
|
||||
<div class="naming-content-stage">
|
||||
<!-- LEFT: HERO AVATAR & BADGES -->
|
||||
<div class="naming-hero-preview">
|
||||
<div class="hero-stage-pedestal">
|
||||
<img src="@CurrentSelectedHeroImg" alt="@CurrentSelectedHero.Name" class="naming-hero-img anim-hero-idle" />
|
||||
</div>
|
||||
<div class="naming-badges-row">
|
||||
<span class="grade-pill-badge">🎒 @SelectedGrade. Ročník</span>
|
||||
<span class="hero-pill-badge">🛡️ @CurrentSelectedHero.Title</span>
|
||||
</div>
|
||||
<div class="naming-stat-summary">
|
||||
<span>❤️ 5 Životov</span>
|
||||
<span>⚡ 10 Útok</span>
|
||||
<span>⏱️ <3s Kritický zásah (150%)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RIGHT: NAME INPUT & ACTION BUTTON -->
|
||||
<div class="naming-form-box">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="heroNameInput">Ako sa volá tvoj hrdina?</label>
|
||||
<div class="name-input-with-dice">
|
||||
<input id="heroNameInput"
|
||||
type="text"
|
||||
class="hero-name-big-input"
|
||||
@bind="HeroName"
|
||||
placeholder="Zadaj meno hrdinu..."
|
||||
maxlength="20" />
|
||||
<button type="button"
|
||||
class="btn-dice-randomizer @(IsRollingDice ? "rolling" : "")"
|
||||
@onclick="RollRandomName"
|
||||
title="Vyžrebovať náhodné meno!">
|
||||
<span class="dice-icon">🎲</span>
|
||||
<span class="dice-label">Náhodné meno</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="quick-names-section">
|
||||
<span class="quick-names-title">Alebo si vyber obľúbené meno:</span>
|
||||
<div class="quick-names-grid">
|
||||
@foreach (var suggestion in QuickNameSuggestions)
|
||||
{
|
||||
<button type="button"
|
||||
class="name-chip-btn @(HeroName == suggestion ? "active-chip" : "")"
|
||||
@onclick="() => SetHeroName(suggestion)">
|
||||
@suggestion
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="naming-action-footer">
|
||||
<button class="btn-grand-start" @onclick="StartQuest">
|
||||
⚔️ VSTÚPIŤ DO HRY A ZAČAŤ VÝPRAVU 🚀
|
||||
</button>
|
||||
<p class="autosave-notice">💾 Tvoj postup a hviezdičky sa automaticky ukladajú na tomto zariadení.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
break;
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public EventCallback<PlayerProfile> OnProfileReady { get; set; }
|
||||
[Parameter] public EventCallback OnCancel { get; set; }
|
||||
|
||||
private enum WizardStep
|
||||
{
|
||||
SelectGrade,
|
||||
SelectHero,
|
||||
NameAndStart
|
||||
}
|
||||
|
||||
private WizardStep CurrentStep { get; set; } = WizardStep.SelectGrade;
|
||||
private int SelectedGrade { get; set; } = 2;
|
||||
private string SelectedHeroId { get; set; } = "knight";
|
||||
private string HeroName { get; set; } = "Mladý Hrdina";
|
||||
private string HeroName { get; set; } = "Udatný Rytier";
|
||||
private bool IsRollingDice { get; set; } = false;
|
||||
|
||||
private Hero CurrentSelectedHero => DataLoader.GetHero(SelectedHeroId) ?? DataLoader.Heroes.FirstOrDefault() ?? new Hero();
|
||||
private string CurrentSelectedHeroImg => $"{CurrentSelectedHero.AssetFolder}_idle_p1.png";
|
||||
|
||||
private readonly Random _random = new();
|
||||
|
||||
private readonly List<string> QuickNameSuggestions = new()
|
||||
{
|
||||
"Arthur", "Eliška", "Maxim", "Sofia", "Oliver",
|
||||
"Viktória", "Lucas", "Nela", "Jakub", "Mia"
|
||||
};
|
||||
|
||||
private readonly List<string> AllHeroNamesPool = new()
|
||||
{
|
||||
// Chlapčenské mená
|
||||
"Arthur", "Maxim", "Oliver", "Lucas", "Leo", "Alex", "Matias", "Michal",
|
||||
"Adam", "Jakub", "Filip", "Damián", "Teodor", "Bruno", "Hugo", "Šimon",
|
||||
"Tobiáš", "Viktor", "Benjamín", "Richard", "Tomáš", "Patrik", "Matej",
|
||||
// Dievčenské mená
|
||||
"Eliška", "Sofia", "Viktória", "Nela", "Mia", "Nina", "Ema", "Tamara",
|
||||
"Laura", "Dorotka", "Linda", "Sára", "Stella", "Lea", "Hana", "Kristína",
|
||||
"Amélia", "Zoja", "Diana", "Barborka", "Zuzka", "Veronika", "Natália",
|
||||
// Hrdinské rozprávkové tituly
|
||||
"Udatný Arthur", "Bystrá Sofia", "Rýchly Alex", "Odvážna Eliška", "Múdry Oliver",
|
||||
"Čarovná Mia", "Hrdina Maxim", "Jasná Stella", "Šampión Leo", "Zlatá Viktória",
|
||||
"Rytier Pravítko", "Mág Číselník", "Lučostrelec Stovka", "Kráľovský Strážca"
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (DataLoader.Heroes.Any())
|
||||
{
|
||||
SelectedHeroId = DataLoader.Heroes.First().Id;
|
||||
UpdateDefaultName();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetGrade(int grade)
|
||||
private void SelectGradeAndProceed(int grade)
|
||||
{
|
||||
SelectedGrade = grade;
|
||||
CurrentStep = WizardStep.SelectHero;
|
||||
}
|
||||
|
||||
private void SelectHero(string heroId)
|
||||
private void SelectHeroAndProceed(string heroId)
|
||||
{
|
||||
SelectedHeroId = heroId;
|
||||
UpdateDefaultName();
|
||||
CurrentStep = WizardStep.NameAndStart;
|
||||
}
|
||||
|
||||
private void UpdateDefaultName()
|
||||
{
|
||||
HeroName = SelectedHeroId switch
|
||||
{
|
||||
"knight" => "Udatný Rytier",
|
||||
"mage" => "Mág Číselník",
|
||||
"archer" => "Bystrý Lučostrelec",
|
||||
_ => "Mladý Hrdina"
|
||||
};
|
||||
}
|
||||
|
||||
private async Task RollRandomName()
|
||||
{
|
||||
IsRollingDice = true;
|
||||
StateHasChanged();
|
||||
|
||||
var available = AllHeroNamesPool.Where(n => n != HeroName).ToList();
|
||||
if (!available.Any()) available = AllHeroNamesPool;
|
||||
|
||||
HeroName = available[_random.Next(available.Count)];
|
||||
|
||||
await Task.Delay(300);
|
||||
IsRollingDice = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void SetHeroName(string name)
|
||||
{
|
||||
HeroName = name;
|
||||
}
|
||||
|
||||
private async Task HandleBackToMenu()
|
||||
{
|
||||
await OnCancel.InvokeAsync();
|
||||
}
|
||||
|
||||
private async Task StartQuest()
|
||||
{
|
||||
var finalName = string.IsNullOrWhiteSpace(HeroName) ? "Mladý Hrdina" : HeroName.Trim();
|
||||
|
||||
var profile = new PlayerProfile
|
||||
{
|
||||
Name = string.IsNullOrWhiteSpace(HeroName) ? "Mladý Hrdina" : HeroName,
|
||||
Name = finalName,
|
||||
SelectedGrade = SelectedGrade,
|
||||
SelectedHeroId = SelectedHeroId,
|
||||
CurrentWorldId = 1,
|
||||
UnlockedLevels = new HashSet<string> { $"{SelectedGrade}-1-1" }
|
||||
UnlockedLevels = new HashSet<string> { $"{SelectedGrade}-1-1" },
|
||||
CompletedLevels = new HashSet<string>()
|
||||
};
|
||||
|
||||
await Storage.SaveProfileAsync(profile);
|
||||
|
||||
@@ -1,63 +1,182 @@
|
||||
@inject IGameDataLoader DataLoader
|
||||
|
||||
<div class="world-map-screen">
|
||||
<!-- Top Player Status Bar -->
|
||||
<!-- TOP STATUS BAR -->
|
||||
<div class="map-top-bar">
|
||||
<div class="player-pill">
|
||||
<span class="avatar-icon">@(Profile.SelectedHeroId == "knight" ? "⚔️" : Profile.SelectedHeroId == "mage" ? "🧙♂️" : "🏹")</span>
|
||||
<img src="@HeroAvatarUrl" alt="Hrdina" class="mini-hero-avatar" />
|
||||
<div class="player-info-text">
|
||||
<span class="player-name">@Profile.Name</span>
|
||||
<span class="grade-tag">@(Profile.SelectedGrade). Ročník</span>
|
||||
<span class="grade-tag">🎒 @(Profile.SelectedGrade). Ročník</span>
|
||||
</div>
|
||||
<div class="stats-pill">
|
||||
<span>⭐ Hviezdy: <strong>@Profile.TotalStars</strong></span>
|
||||
</div>
|
||||
<button class="btn-change-hero" @onclick="OnChangeHero">Zmeniť hrdinu 🔄</button>
|
||||
</div>
|
||||
|
||||
<!-- Worlds Container -->
|
||||
<div class="worlds-carousel">
|
||||
@foreach (var world in Worlds)
|
||||
{
|
||||
<div class="world-card">
|
||||
<div class="world-header">
|
||||
<h2>@world.Name</h2>
|
||||
<p>@world.Description</p>
|
||||
<div class="stats-pill-group">
|
||||
<div class="stat-badge stars-badge">
|
||||
<span>⭐ <strong>@Profile.TotalStars</strong> Hviezd</span>
|
||||
</div>
|
||||
<div class="stat-badge gold-badge">
|
||||
<span>💰 <strong>@Profile.Gold</strong> Zlata</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="levels-path">
|
||||
@foreach (var level in world.Levels)
|
||||
{
|
||||
bool isUnlocked = Profile.UnlockedLevels.Contains(level.Id);
|
||||
bool isCompleted = Profile.CompletedLevels.Contains(level.Id);
|
||||
|
||||
<button class="level-node @(level.IsBoss ? "boss-node" : "") @(isUnlocked ? "unlocked" : "locked") @(isCompleted ? "completed" : "")"
|
||||
disabled="@(!isUnlocked)"
|
||||
@onclick="() => SelectLevel(level)">
|
||||
<div class="node-icon">
|
||||
@if (isCompleted)
|
||||
<div class="map-top-actions">
|
||||
<button class="btn-top-action" @onclick="OnChangeHero" title="Zmeniť ročník alebo hrdinu">
|
||||
🎒 Zmeniť hrdinu
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MAIN WORLD MAP CONTENT AREA -->
|
||||
<div class="world-map-content">
|
||||
<!-- WORLD SELECTION TABS -->
|
||||
<div class="world-tabs-nav">
|
||||
@for (int i = 0; i < Worlds.Count; i++)
|
||||
{
|
||||
<span>⭐</span>
|
||||
}
|
||||
else if (level.IsBoss)
|
||||
var w = Worlds[i];
|
||||
var worldIndex = i + 1;
|
||||
var isSelected = SelectedWorldIndex == worldIndex;
|
||||
var isWorldUnlocked = w.Levels.Any(l => Profile.UnlockedLevels.Contains(l.Id));
|
||||
var completedInWorld = w.Levels.Count(l => Profile.CompletedLevels.Contains(l.Id));
|
||||
var totalInWorld = w.Levels.Count;
|
||||
var isWorldCompleted = totalInWorld > 0 && completedInWorld == totalInWorld;
|
||||
|
||||
<button class="world-tab-btn @(isSelected ? "active" : "") @(isWorldUnlocked ? "unlocked" : "locked") @(isWorldCompleted ? "world-completed" : "")"
|
||||
disabled="@(!isWorldUnlocked)"
|
||||
@onclick="() => SelectWorld(worldIndex)">
|
||||
<span class="world-tab-icon">
|
||||
@if (isWorldCompleted)
|
||||
{
|
||||
<span>👑</span>
|
||||
<span>🌟</span>
|
||||
}
|
||||
else if (isUnlocked)
|
||||
{
|
||||
<span>⚔️</span>
|
||||
}
|
||||
else
|
||||
else if (!isWorldUnlocked)
|
||||
{
|
||||
<span>🔒</span>
|
||||
}
|
||||
</div>
|
||||
<span class="level-title">@level.Name</span>
|
||||
@if (level.IsBoss)
|
||||
else
|
||||
{
|
||||
<span class="boss-tag">BOSS</span>
|
||||
<span>@(worldIndex == 1 ? "🌸" : worldIndex == 2 ? "🌲" : worldIndex == 3 ? "🌊" : worldIndex == 4 ? "⛰️" : "🏰")</span>
|
||||
}
|
||||
</span>
|
||||
<span class="world-tab-label">Svet @worldIndex</span>
|
||||
<span class="world-tab-progress">@completedInWorld/@totalInWorld</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- CURRENT SELECTED WORLD SHOWCASE -->
|
||||
@if (ActiveWorld != null)
|
||||
{
|
||||
var completedCount = ActiveWorld.Levels.Count(l => Profile.CompletedLevels.Contains(l.Id));
|
||||
var totalCount = ActiveWorld.Levels.Count;
|
||||
var progressPercent = totalCount > 0 ? (int)((double)completedCount / totalCount * 100) : 0;
|
||||
|
||||
<div class="active-world-card parchment-container">
|
||||
<!-- WORLD BANNER HEADER -->
|
||||
<div class="world-header-row">
|
||||
<div class="world-title-col">
|
||||
<h2 class="active-world-title">@ActiveWorld.Name</h2>
|
||||
<p class="active-world-desc">@ActiveWorld.Description</p>
|
||||
</div>
|
||||
|
||||
<div class="world-progress-col">
|
||||
<div class="progress-label-row">
|
||||
<span>Postup vo svete:</span>
|
||||
<strong>@completedCount z @totalCount splnených</strong>
|
||||
</div>
|
||||
<div class="world-progress-bar">
|
||||
<div class="world-progress-fill" style="width: @(progressPercent)%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LEVELS RICH CARDS GRID -->
|
||||
<div class="levels-rich-grid">
|
||||
@foreach (var level in ActiveWorld.Levels)
|
||||
{
|
||||
var isUnlocked = Profile.UnlockedLevels.Contains(level.Id);
|
||||
var isCompleted = Profile.CompletedLevels.Contains(level.Id);
|
||||
var enemyImg = $"{level.Enemy.AssetFolder}_idle_p1.png";
|
||||
var mathDesc = GetMathDescription(level.MathConfig);
|
||||
|
||||
<div class="level-rich-card @(level.IsBoss ? "boss-card" : "") @(isCompleted ? "status-completed" : isUnlocked ? "status-current" : "status-locked")">
|
||||
|
||||
<!-- CARD STATUS BADGE -->
|
||||
<div class="card-status-banner">
|
||||
@if (isCompleted)
|
||||
{
|
||||
<span class="badge-completed">🏆 PREKONANÝ</span>
|
||||
<span class="stars-awarded">@(level.IsBoss ? "⭐⭐⭐" : "⭐")</span>
|
||||
}
|
||||
else if (level.IsBoss)
|
||||
{
|
||||
<span class="badge-boss">👑 VEĽKÝ BOSS</span>
|
||||
}
|
||||
else if (isUnlocked)
|
||||
{
|
||||
<span class="badge-active">⚔️ NOVÁ VÝZVA</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge-locked">🔒 ZAMKNUTÉ</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- ENEMY AVATAR STAGE -->
|
||||
<div class="level-enemy-stage">
|
||||
<div class="enemy-avatar-wrapper @(isCompleted ? "defeated-glow" : isUnlocked ? "active-glow" : "locked-silhouette")">
|
||||
<img src="@enemyImg" alt="@level.Enemy.Name" class="level-enemy-img @(isUnlocked && !isCompleted ? "anim-hero-idle" : "")" />
|
||||
@if (!isUnlocked)
|
||||
{
|
||||
<div class="lock-overlay">🔒</div>
|
||||
}
|
||||
@if (isCompleted)
|
||||
{
|
||||
<div class="check-overlay">✓</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LEVEL DETAILS -->
|
||||
<div class="level-info-body">
|
||||
<div class="level-number-tag">Level @level.LevelNumber</div>
|
||||
<h3 class="level-name-title">@level.Name</h3>
|
||||
<div class="level-enemy-name">Protivník: <strong>@level.Enemy.Name</strong></div>
|
||||
|
||||
<div class="level-math-pill">
|
||||
@mathDesc
|
||||
</div>
|
||||
|
||||
<div class="level-stats-row">
|
||||
<span class="stat-bubble">❤️ @level.Enemy.MaxHp HP</span>
|
||||
<span class="stat-bubble">🎯 @level.RequiredCorrectAnswers správne</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ACTION BUTTON -->
|
||||
<div class="level-card-footer">
|
||||
@if (isCompleted)
|
||||
{
|
||||
<button class="btn-level-action btn-replay" @onclick="() => SelectLevel(level)">
|
||||
🔁 Hrať znova (Tréning)
|
||||
</button>
|
||||
}
|
||||
else if (isUnlocked)
|
||||
{
|
||||
<button class="btn-level-action btn-battle @(level.IsBoss ? "btn-boss-battle" : "")" @onclick="() => SelectLevel(level)">
|
||||
⚔️ VYZVAŤ NA SÚBOJ! ➜
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn-level-action btn-locked" disabled="true">
|
||||
🔒 Splň predchádzajúci level
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -69,9 +188,81 @@
|
||||
[Parameter] public EventCallback OnChangeHero { get; set; }
|
||||
|
||||
private List<World> Worlds => DataLoader.GetWorldsForGrade(Profile.SelectedGrade);
|
||||
private int SelectedWorldIndex { get; set; } = 1;
|
||||
|
||||
private World? ActiveWorld => Worlds.FirstOrDefault(w => w.Id == SelectedWorldIndex)
|
||||
?? Worlds.FirstOrDefault();
|
||||
|
||||
private string HeroAvatarUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
var hero = DataLoader.GetHero(Profile.SelectedHeroId) ?? DataLoader.Heroes.FirstOrDefault();
|
||||
return hero != null ? $"{hero.AssetFolder}_idle_p1.png" : "assets/images/heroes/knight_idle_p1.png";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
// Automatically select the world that has the highest unlocked level
|
||||
if (Worlds.Any())
|
||||
{
|
||||
var highestWorldWithUnlocked = Worlds
|
||||
.Where(w => w.Levels.Any(l => Profile.UnlockedLevels.Contains(l.Id)))
|
||||
.OrderByDescending(w => w.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (highestWorldWithUnlocked != null)
|
||||
{
|
||||
SelectedWorldIndex = highestWorldWithUnlocked.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedWorldIndex = Worlds.First().Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectWorld(int worldIndex)
|
||||
{
|
||||
SelectedWorldIndex = worldIndex;
|
||||
}
|
||||
|
||||
private async Task SelectLevel(Level level)
|
||||
{
|
||||
await OnLevelSelected.InvokeAsync(level);
|
||||
}
|
||||
|
||||
private string GetMathDescription(MathConfig config)
|
||||
{
|
||||
if (config.Operations.Contains("<") || config.Operations.Contains(">") || config.Operations.Contains("="))
|
||||
{
|
||||
return "⚖️ Porovnávanie čísel (< > =)";
|
||||
}
|
||||
if (config.Operations.Contains("*") && config.Operations.Contains("/"))
|
||||
{
|
||||
return "✖️ ➗ Násobilka a delenie";
|
||||
}
|
||||
if (config.Operations.Contains("*"))
|
||||
{
|
||||
return "✖️ Malá násobilka";
|
||||
}
|
||||
if (config.Operations.Contains("/"))
|
||||
{
|
||||
return "➗ Delenie čísel";
|
||||
}
|
||||
if (config.Operations.Contains("+") && config.Operations.Contains("-"))
|
||||
{
|
||||
return $"➕ ➖ Sčítanie a odčítanie do {config.MaxSum}";
|
||||
}
|
||||
if (config.Operations.Contains("+"))
|
||||
{
|
||||
return $"➕ Sčítanie do {config.MaxSum}";
|
||||
}
|
||||
if (config.Operations.Contains("-"))
|
||||
{
|
||||
return $"➖ Odčítanie do {config.MaxA}";
|
||||
}
|
||||
return "➕ Matematická výzva";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
}
|
||||
else if (CurrentScreen == ScreenType.CharacterSelect)
|
||||
{
|
||||
<CharacterSelect OnProfileReady="HandleProfileReady" />
|
||||
<CharacterSelect OnProfileReady="HandleProfileReady"
|
||||
OnCancel="() => CurrentScreen = ScreenType.MainMenu" />
|
||||
}
|
||||
else if (CurrentScreen == ScreenType.WorldMap)
|
||||
{
|
||||
@@ -34,11 +35,42 @@
|
||||
else if (CurrentScreen == ScreenType.Battle && SelectedLevel != null)
|
||||
{
|
||||
var hero = DataLoader.GetHero(Profile.SelectedHeroId) ?? DataLoader.Heroes.First();
|
||||
var worlds = DataLoader.GetWorldsForGrade(Profile.SelectedGrade);
|
||||
var currentWorld = worlds.FirstOrDefault(w => w.Levels.Any(l => l.Id == SelectedLevel.Id));
|
||||
var bg = currentWorld?.Background ?? "assets/images/backgrounds/world1_meadow.jpg";
|
||||
|
||||
<BattleArena Hero="hero"
|
||||
CurrentLevel="SelectedLevel"
|
||||
PlayerGrade="Profile.SelectedGrade"
|
||||
BackgroundImage="@bg"
|
||||
Config="DataLoader.Config"
|
||||
OnReturnToMap="() => CurrentScreen = ScreenType.WorldMap"
|
||||
OnLevelCompleted="HandleLevelCompleted" />
|
||||
OnLevelCompleted="HandleLevelCompleted"
|
||||
OnNextLevelRequested="HandleNextLevelRequested" />
|
||||
}
|
||||
|
||||
<!-- FAIRYTALE LEVEL TRANSITION SCREEN -->
|
||||
@if (IsTransitioning)
|
||||
{
|
||||
var hero = DataLoader.GetHero(Profile.SelectedHeroId) ?? DataLoader.Heroes.FirstOrDefault();
|
||||
var heroAvatar = hero != null ? $"{hero.AssetFolder}_idle_p1.png" : "assets/images/heroes/knight_idle_p1.png";
|
||||
|
||||
<div class="transition-screen-overlay anim-fade-in">
|
||||
<div class="transition-parchment-box anim-victory-modal-pop">
|
||||
<div class="transition-hero-marching">
|
||||
<img src="@heroAvatar"
|
||||
class="marching-hero-img anim-hero-march"
|
||||
alt="Hrdina na ceste" />
|
||||
</div>
|
||||
<h2 class="transition-title">🗺️ Vstupuješ do novej oblasti...</h2>
|
||||
<p class="transition-target">📍 @TransitionTargetText</p>
|
||||
<div class="transition-sparkles">
|
||||
<span class="sparkle">✨</span>
|
||||
<span class="sparkle">⭐</span>
|
||||
<span class="sparkle">✨</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -57,6 +89,9 @@
|
||||
private PlayerProfile Profile { get; set; } = new();
|
||||
private Level? SelectedLevel { get; set; }
|
||||
|
||||
private bool IsTransitioning { get; set; } = false;
|
||||
private string TransitionTargetText { get; set; } = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
@@ -85,19 +120,44 @@
|
||||
await Storage.SaveProfileAsync(Profile);
|
||||
}
|
||||
|
||||
private void HandleLevelSelected(Level level)
|
||||
private async Task HandleLevelSelected(Level level)
|
||||
{
|
||||
TransitionTargetText = $"{level.Name} (Protivník: {level.Enemy.Name})";
|
||||
IsTransitioning = true;
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(850);
|
||||
|
||||
SelectedLevel = level;
|
||||
CurrentScreen = ScreenType.Battle;
|
||||
IsTransitioning = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task HandleLevelCompleted(Level completedLevel)
|
||||
{
|
||||
UnlockNextLevel(completedLevel);
|
||||
await Storage.SaveProfileAsync(Profile);
|
||||
CurrentScreen = ScreenType.WorldMap;
|
||||
}
|
||||
|
||||
private async Task HandleNextLevelRequested(Level nextLevel)
|
||||
{
|
||||
if (SelectedLevel != null)
|
||||
{
|
||||
UnlockNextLevel(SelectedLevel);
|
||||
await Storage.SaveProfileAsync(Profile);
|
||||
}
|
||||
|
||||
await HandleLevelSelected(nextLevel);
|
||||
}
|
||||
|
||||
private void UnlockNextLevel(Level completedLevel)
|
||||
{
|
||||
Profile.CompletedLevels.Add(completedLevel.Id);
|
||||
Profile.TotalStars += completedLevel.IsBoss ? 3 : 1;
|
||||
Profile.Gold += completedLevel.IsBoss ? 50 : 20;
|
||||
|
||||
// Unlock next level in current world
|
||||
var worlds = DataLoader.GetWorldsForGrade(Profile.SelectedGrade);
|
||||
var currentWorld = worlds.FirstOrDefault(w => w.Levels.Any(l => l.Id == completedLevel.Id));
|
||||
if (currentWorld != null)
|
||||
@@ -109,7 +169,6 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unlock first level of next world
|
||||
var nextWorldIndex = worlds.IndexOf(currentWorld) + 1;
|
||||
if (nextWorldIndex < worlds.Count && worlds[nextWorldIndex].Levels.Any())
|
||||
{
|
||||
@@ -117,8 +176,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Storage.SaveProfileAsync(Profile);
|
||||
CurrentScreen = ScreenType.WorldMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ public interface IGameDataLoader
|
||||
List<Hero> Heroes { get; }
|
||||
List<World> GetWorldsForGrade(int grade);
|
||||
Hero? GetHero(string id);
|
||||
Level? GetNextLevel(int grade, string currentLevelId);
|
||||
}
|
||||
|
||||
public class GameDataLoader : IGameDataLoader
|
||||
@@ -60,4 +61,29 @@ public class GameDataLoader : IGameDataLoader
|
||||
return _heroes.FirstOrDefault(h => h.Id.Equals(id, StringComparison.OrdinalIgnoreCase))
|
||||
?? _heroes.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Level? GetNextLevel(int grade, string currentLevelId)
|
||||
{
|
||||
var worlds = GetWorldsForGrade(grade);
|
||||
for (int w = 0; w < worlds.Count; w++)
|
||||
{
|
||||
var world = worlds[w];
|
||||
for (int l = 0; l < world.Levels.Count; l++)
|
||||
{
|
||||
if (world.Levels[l].Id == currentLevelId)
|
||||
{
|
||||
if (l + 1 < world.Levels.Count)
|
||||
{
|
||||
return world.Levels[l + 1];
|
||||
}
|
||||
else if (w + 1 < worlds.Count && worlds[w + 1].Levels.Any())
|
||||
{
|
||||
return worlds[w + 1].Levels.First();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
|
After Width: | Height: | Size: 966 KiB |
@@ -2,54 +2,24 @@
|
||||
{
|
||||
"id": 1,
|
||||
"grade": 1,
|
||||
"name": "Rozprávková lúka (Počítanie do 10)",
|
||||
"description": "Jednoduché sčítanie a odčítanie do 10 pre malých prváčikov.",
|
||||
"name": "Svet 1: Rozprávková lúka (Do 10)",
|
||||
"description": "Základné sčítanie a odčítanie v obore do 10 pre prváčikov.",
|
||||
"background": "assets/images/backgrounds/world1_meadow.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "1-1-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Lúčny Motýlik",
|
||||
"enemy": {
|
||||
"id": "meadow_butterfly",
|
||||
"name": "Lúčny Motýlik",
|
||||
"maxHp": 20,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+"],
|
||||
"minA": 1,
|
||||
"maxA": 5,
|
||||
"minB": 1,
|
||||
"maxB": 5,
|
||||
"maxSum": 10,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"enemy": { "id": "meadow_butterfly", "name": "Lúčny Motýlik", "maxHp": 20, "attackPower": 1, "assetFolder": "assets/images/enemies/goblin" },
|
||||
"mathConfig": { "operations": ["+"], "minA": 1, "maxA": 5, "minB": 1, "maxB": 5, "maxSum": 10, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 3
|
||||
},
|
||||
{
|
||||
"id": "1-1-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Zvedavý Zajačik",
|
||||
"enemy": {
|
||||
"id": "curious_bunny",
|
||||
"name": "Zvedavý Zajačik",
|
||||
"maxHp": 25,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 2,
|
||||
"maxA": 10,
|
||||
"minB": 1,
|
||||
"maxB": 5,
|
||||
"maxSum": 10,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"enemy": { "id": "curious_bunny", "name": "Zvedavý Zajačik", "maxHp": 25, "attackPower": 1, "assetFolder": "assets/images/enemies/slime" },
|
||||
"mathConfig": { "operations": ["+", "-"], "minA": 2, "maxA": 10, "minB": 1, "maxB": 5, "maxSum": 10, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 3
|
||||
},
|
||||
{
|
||||
@@ -57,23 +27,8 @@
|
||||
"levelNumber": 3,
|
||||
"name": "Lesný Medveď (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "gentle_bear_boss",
|
||||
"name": "Strážca Lúky",
|
||||
"maxHp": 40,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 3,
|
||||
"maxA": 10,
|
||||
"minB": 1,
|
||||
"maxB": 5,
|
||||
"maxSum": 10,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"enemy": { "id": "gentle_bear_boss", "name": "Strážca Lúky", "maxHp": 40, "attackPower": 1, "assetFolder": "assets/images/enemies/golem" },
|
||||
"mathConfig": { "operations": ["+", "-"], "minA": 3, "maxA": 10, "minB": 1, "maxB": 5, "maxSum": 10, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 4
|
||||
}
|
||||
]
|
||||
@@ -81,32 +36,86 @@
|
||||
{
|
||||
"id": 2,
|
||||
"grade": 1,
|
||||
"name": "Slnečná čistinka (Počítanie do 20 bez prechodu)",
|
||||
"description": "Sčítanie a odčítanie v obore do 20 (napr. 10 + 4, 15 - 3).",
|
||||
"name": "Svet 2: Slnečná čistinka (Do 20 bez prechodu)",
|
||||
"description": "Sčítanie a odčítanie v obore do 20 bez prechodu cez desiatku.",
|
||||
"background": "assets/images/backgrounds/world2_forest.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "1-2-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Lesný Škriatok",
|
||||
"enemy": {
|
||||
"id": "forest_gnome",
|
||||
"name": "Lesný Škriatok",
|
||||
"maxHp": 30,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 10,
|
||||
"maxA": 19,
|
||||
"minB": 1,
|
||||
"maxB": 5,
|
||||
"maxSum": 20,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"enemy": { "id": "forest_gnome", "name": "Lesný Škriatok", "maxHp": 30, "attackPower": 1, "assetFolder": "assets/images/enemies/goblin" },
|
||||
"mathConfig": { "operations": ["+", "-"], "minA": 10, "maxA": 19, "minB": 1, "maxB": 5, "maxSum": 20, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "1-2-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Kráľovský Ježko",
|
||||
"enemy": { "id": "royal_hedgehog", "name": "Kráľovský Ježko", "maxHp": 35, "attackPower": 1, "assetFolder": "assets/images/enemies/slime" },
|
||||
"mathConfig": { "operations": ["+", "-"], "minA": 11, "maxA": 19, "minB": 1, "maxB": 8, "maxSum": 20, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"grade": 1,
|
||||
"name": "Svet 3: Zrkadlové jazierko (Porovnávanie < > =)",
|
||||
"description": "Zisťovanie, ktoré číslo je väčšie, menšie alebo rovnaké.",
|
||||
"background": "assets/images/backgrounds/world3_river.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "1-3-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Vodná Víla",
|
||||
"enemy": { "id": "water_fairy", "name": "Vodná Víla", "maxHp": 30, "attackPower": 1, "assetFolder": "assets/images/enemies/goblin" },
|
||||
"mathConfig": { "operations": ["<", ">", "="], "minA": 1, "maxA": 20, "minB": 1, "maxB": 20, "inputType": "MultipleChoice" },
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "1-3-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Riečny Had (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": { "id": "river_serpent_boss", "name": "Riečny Had", "maxHp": 50, "attackPower": 1, "assetFolder": "assets/images/enemies/golem" },
|
||||
"mathConfig": { "operations": ["<", ">", "="], "minA": 5, "maxA": 20, "minB": 5, "maxB": 20, "inputType": "MultipleChoice" },
|
||||
"requiredCorrectAnswers": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"grade": 1,
|
||||
"name": "Svet 4: Horská pevnosť (Desiatky)",
|
||||
"description": "Počítanie po desiatkach do 100 (10, 20, 30...).",
|
||||
"background": "assets/images/backgrounds/world1_meadow.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "1-4-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Kamenný Strážca",
|
||||
"enemy": { "id": "stone_watcher", "name": "Kamenný Strážca", "maxHp": 35, "attackPower": 1, "assetFolder": "assets/images/enemies/golem" },
|
||||
"mathConfig": { "operations": ["+", "-"], "minA": 10, "maxA": 50, "minB": 10, "maxB": 40, "maxSum": 100, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"grade": 1,
|
||||
"name": "Svet 5: Kráľovský Hrad (Finále 1. ročníka)",
|
||||
"description": "Veľký záverečný test všetkých zručností prvého ročníka!",
|
||||
"background": "assets/images/backgrounds/title_screen_bg.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "1-5-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Kráľovský Drak (Veľký Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": { "id": "king_dragon_boss", "name": "Kráľovský Drak", "maxHp": 60, "attackPower": 1, "assetFolder": "assets/images/enemies/golem" },
|
||||
"mathConfig": { "operations": ["+", "-"], "minA": 5, "maxA": 20, "minB": 1, "maxB": 10, "maxSum": 20, "allowCarryOver": false, "inputType": "DirectInput" },
|
||||
"requiredCorrectAnswers": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": 1,
|
||||
"grade": 2,
|
||||
"name": "Lúka sčítania a odčítania",
|
||||
"name": "Svet 1: Lúka sčítania a odčítania (Do 20 s prechodom)",
|
||||
"description": "Základné sčítanie a odčítanie do 20 s prechodom cez desiatku.",
|
||||
"background": "assets/images/backgrounds/world1_meadow.jpg",
|
||||
"levels": [
|
||||
@@ -19,10 +19,10 @@
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+"],
|
||||
"minA": 1,
|
||||
"maxA": 10,
|
||||
"minB": 1,
|
||||
"maxB": 10,
|
||||
"minA": 2,
|
||||
"maxA": 9,
|
||||
"minB": 2,
|
||||
"maxB": 9,
|
||||
"maxSum": 20,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
@@ -43,9 +43,9 @@
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 5,
|
||||
"maxA": 20,
|
||||
"minB": 1,
|
||||
"maxB": 10,
|
||||
"maxA": 18,
|
||||
"minB": 2,
|
||||
"maxB": 9,
|
||||
"maxSum": 20,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
@@ -55,21 +55,21 @@
|
||||
{
|
||||
"id": "2-1-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Kamenný Golem (Boss)",
|
||||
"name": "Golem Čísel (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "stone_golem_boss",
|
||||
"name": "Golem Čísiel",
|
||||
"name": "Golem Čísel",
|
||||
"maxHp": 60,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 8,
|
||||
"minA": 6,
|
||||
"maxA": 20,
|
||||
"minB": 4,
|
||||
"maxB": 10,
|
||||
"minB": 3,
|
||||
"maxB": 9,
|
||||
"maxSum": 20,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
@@ -81,20 +81,63 @@
|
||||
{
|
||||
"id": 2,
|
||||
"grade": 2,
|
||||
"name": "Les porovnávania a rovností",
|
||||
"description": "Porovnávanie čísel pomocou znakov <, >, = a dopĺňanie do desiatky.",
|
||||
"name": "Svet 2: Les porovnávania (Do 100)",
|
||||
"description": "Porovnávanie čísel pomocou znakov <, >, = v obore do 100.",
|
||||
"background": "assets/images/backgrounds/world2_forest.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "2-2-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Múdra Sova",
|
||||
"name": "Lesný Goblin",
|
||||
"enemy": {
|
||||
"id": "wise_owl",
|
||||
"name": "Múdra Sova",
|
||||
"maxHp": 30,
|
||||
"id": "forest_goblin_comp",
|
||||
"name": "Lesný Goblin",
|
||||
"maxHp": 35,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/owl"
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["<", ">", "="],
|
||||
"minA": 1,
|
||||
"maxA": 50,
|
||||
"minB": 1,
|
||||
"maxB": 50,
|
||||
"inputType": "MultipleChoice"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "2-2-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Slizký Strážca",
|
||||
"enemy": {
|
||||
"id": "slime_comp_watcher",
|
||||
"name": "Slizký Strážca",
|
||||
"maxHp": 40,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["<", ">", "="],
|
||||
"minA": 20,
|
||||
"maxA": 100,
|
||||
"minB": 20,
|
||||
"maxB": 100,
|
||||
"inputType": "MultipleChoice"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "2-2-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Strážca Hvozdu (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "forest_golem_comp_boss",
|
||||
"name": "Strážca Hvozdu",
|
||||
"maxHp": 55,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["<", ">", "="],
|
||||
@@ -104,7 +147,235 @@
|
||||
"maxB": 100,
|
||||
"inputType": "MultipleChoice"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"grade": 2,
|
||||
"name": "Svet 3: Riečna zátoka (Do 100 bez prechodu)",
|
||||
"description": "Sčítanie a odčítanie desiatok a dvojciferných čísel bez prechodu.",
|
||||
"background": "assets/images/backgrounds/world3_river.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "2-3-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Riečny Goblin",
|
||||
"enemy": {
|
||||
"id": "river_goblin_easy",
|
||||
"name": "Riečny Goblin",
|
||||
"maxHp": 35,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 10,
|
||||
"maxA": 80,
|
||||
"minB": 1,
|
||||
"maxB": 9,
|
||||
"maxSum": 100,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "2-3-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Kvapkový Sliz",
|
||||
"enemy": {
|
||||
"id": "droplet_slime",
|
||||
"name": "Kvapkový Sliz",
|
||||
"maxHp": 45,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 20,
|
||||
"maxA": 70,
|
||||
"minB": 10,
|
||||
"maxB": 25,
|
||||
"maxSum": 100,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "2-3-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Balvanový Netvor (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "river_golem_boss",
|
||||
"name": "Balvanový Netvor",
|
||||
"maxHp": 65,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 20,
|
||||
"maxA": 90,
|
||||
"minB": 5,
|
||||
"maxB": 30,
|
||||
"maxSum": 100,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"grade": 2,
|
||||
"name": "Svet 4: Horský priesmyk (Do 100 s prechodom)",
|
||||
"description": "Sčítanie a odčítanie s prechodom cez desiatku v obore do 100.",
|
||||
"background": "assets/images/backgrounds/world1_meadow.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "2-4-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Horský Goblin",
|
||||
"enemy": {
|
||||
"id": "mountain_goblin",
|
||||
"name": "Horský Goblin",
|
||||
"maxHp": 40,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 15,
|
||||
"maxA": 75,
|
||||
"minB": 4,
|
||||
"maxB": 9,
|
||||
"maxSum": 100,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "2-4-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Magický Horský Sliz",
|
||||
"enemy": {
|
||||
"id": "mountain_magic_slime",
|
||||
"name": "Magický Horský Sliz",
|
||||
"maxHp": 50,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 20,
|
||||
"maxA": 85,
|
||||
"minB": 6,
|
||||
"maxB": 15,
|
||||
"maxSum": 100,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
},
|
||||
{
|
||||
"id": "2-4-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Horský Obor (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "mountain_giant_boss",
|
||||
"name": "Horský Obor",
|
||||
"maxHp": 70,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 25,
|
||||
"maxA": 90,
|
||||
"minB": 8,
|
||||
"maxB": 25,
|
||||
"maxSum": 100,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"grade": 2,
|
||||
"name": "Svet 5: Hrad malej násobilky (Úvod do násobenia)",
|
||||
"description": "Základy násobenia číslami 2, 3, 5 a 10.",
|
||||
"background": "assets/images/backgrounds/title_screen_bg.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "2-5-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Hradný Strážca",
|
||||
"enemy": {
|
||||
"id": "castle_guard_goblin",
|
||||
"name": "Hradný Strážca",
|
||||
"maxHp": 40,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*"],
|
||||
"factors": [2, 5],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "2-5-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Kráľovský Sliz",
|
||||
"enemy": {
|
||||
"id": "royal_castle_slime",
|
||||
"name": "Kráľovský Sliz",
|
||||
"maxHp": 50,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*"],
|
||||
"factors": [2, 3, 5, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
},
|
||||
{
|
||||
"id": "2-5-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Veľký Hradný Pán (Finále 2. ročníka)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "castle_lord_boss",
|
||||
"name": "Veľký Hradný Pán",
|
||||
"maxHp": 75,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*"],
|
||||
"factors": [2, 3, 5, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
{
|
||||
"id": 1,
|
||||
"grade": 3,
|
||||
"name": "Rieka malej násobilky (2, 3, 4, 5)",
|
||||
"description": "Základy násobenia a delenia číslami 2, 3, 4, 5.",
|
||||
"name": "Svet 1: Rieka malej násobilky (2, 3, 4, 5)",
|
||||
"description": "Základy násobenia a delenia číslami 2, 3, 4 a 5.",
|
||||
"background": "assets/images/backgrounds/world3_river.jpg",
|
||||
"levels": [
|
||||
{
|
||||
@@ -11,11 +11,11 @@
|
||||
"levelNumber": 1,
|
||||
"name": "Riečny Škriatok",
|
||||
"enemy": {
|
||||
"id": "river_sprite",
|
||||
"id": "river_sprite_goblin",
|
||||
"name": "Riečny Škriatok",
|
||||
"maxHp": 30,
|
||||
"maxHp": 35,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/sprite"
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*"],
|
||||
@@ -29,13 +29,34 @@
|
||||
{
|
||||
"id": "3-1-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Vodník Násobka",
|
||||
"name": "Vodný Slizík",
|
||||
"enemy": {
|
||||
"id": "water_demon",
|
||||
"name": "Vodník Násobka",
|
||||
"maxHp": 40,
|
||||
"id": "water_slime_div",
|
||||
"name": "Vodný Slizík",
|
||||
"maxHp": 45,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/water_demon"
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["/"],
|
||||
"factors": [2, 3, 4, 5],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "3-1-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Jazerný Strážca (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "lake_golem_boss",
|
||||
"name": "Jazerný Strážca",
|
||||
"maxHp": 65,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*", "/"],
|
||||
@@ -45,22 +66,71 @@
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "3-1-3",
|
||||
"id": 2,
|
||||
"grade": 3,
|
||||
"name": "Svet 2: Les veľkej násobilky (6, 7, 8, 9, 10)",
|
||||
"description": "Násobenie a delenie vyššími číslami 6 až 10.",
|
||||
"background": "assets/images/backgrounds/world2_forest.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "3-2-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Lesný Piadimužík",
|
||||
"enemy": {
|
||||
"id": "forest_dwarf_goblin",
|
||||
"name": "Lesný Piadimužík",
|
||||
"maxHp": 40,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*"],
|
||||
"factors": [6, 7, 8, 9, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "3-2-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Živicový Sliz",
|
||||
"enemy": {
|
||||
"id": "resin_slime_div",
|
||||
"name": "Živicový Sliz",
|
||||
"maxHp": 50,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["/"],
|
||||
"factors": [6, 7, 8, 9, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
},
|
||||
{
|
||||
"id": "3-2-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Jazerný Drak (Boss)",
|
||||
"name": "Starý Lesný Golem (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "lake_dragon_boss",
|
||||
"name": "Jazerný Drak",
|
||||
"maxHp": 60,
|
||||
"id": "ancient_forest_golem_boss",
|
||||
"name": "Starý Lesný Golem",
|
||||
"maxHp": 70,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/dragon"
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*", "/"],
|
||||
"factors": [2, 3, 4, 5],
|
||||
"factors": [6, 7, 8, 9, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
@@ -68,5 +138,237 @@
|
||||
"requiredCorrectAnswers": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"grade": 3,
|
||||
"name": "Svet 3: Krištáľové údolie (Počítanie do 1000)",
|
||||
"description": "Sčítanie a odčítanie v obore do 1000 po stovkách a desiatkach.",
|
||||
"background": "assets/images/backgrounds/world1_meadow.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "3-3-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Jaskynný Goblin",
|
||||
"enemy": {
|
||||
"id": "cave_goblin_1000",
|
||||
"name": "Jaskynný Goblin",
|
||||
"maxHp": 45,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 100,
|
||||
"maxA": 800,
|
||||
"minB": 50,
|
||||
"maxB": 200,
|
||||
"maxSum": 1000,
|
||||
"allowCarryOver": false,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "3-3-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Trblietavý Sliz",
|
||||
"enemy": {
|
||||
"id": "glitter_slime_1000",
|
||||
"name": "Trblietavý Sliz",
|
||||
"maxHp": 55,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 200,
|
||||
"maxA": 900,
|
||||
"minB": 100,
|
||||
"maxB": 300,
|
||||
"maxSum": 1000,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
},
|
||||
{
|
||||
"id": "3-3-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Kryštálový Golem (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "crystal_golem_boss",
|
||||
"name": "Kryštálový Golem",
|
||||
"maxHp": 75,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-"],
|
||||
"minA": 150,
|
||||
"maxA": 850,
|
||||
"minB": 50,
|
||||
"maxB": 350,
|
||||
"maxSum": 1000,
|
||||
"allowCarryOver": true,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"grade": 3,
|
||||
"name": "Svet 4: Veterné bralo (Porovnávanie do 1000)",
|
||||
"description": "Porovnávanie veľkých trojciferných čísel pomocou znakov <, >, =.",
|
||||
"background": "assets/images/backgrounds/world3_river.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "3-4-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Veterný Škriatok",
|
||||
"enemy": {
|
||||
"id": "wind_sprite_goblin",
|
||||
"name": "Veterný Škriatok",
|
||||
"maxHp": 40,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["<", ">", "="],
|
||||
"minA": 100,
|
||||
"maxA": 999,
|
||||
"minB": 100,
|
||||
"maxB": 999,
|
||||
"inputType": "MultipleChoice"
|
||||
},
|
||||
"requiredCorrectAnswers": 4
|
||||
},
|
||||
{
|
||||
"id": "3-4-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Búrkový Sliz",
|
||||
"enemy": {
|
||||
"id": "storm_slime_comp",
|
||||
"name": "Búrkový Sliz",
|
||||
"maxHp": 50,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["<", ">", "="],
|
||||
"minA": 300,
|
||||
"maxA": 1000,
|
||||
"minB": 300,
|
||||
"maxB": 1000,
|
||||
"inputType": "MultipleChoice"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
},
|
||||
{
|
||||
"id": "3-4-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Hromový Golem (Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "thunder_golem_boss",
|
||||
"name": "Hromový Golem",
|
||||
"maxHp": 75,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["<", ">", "="],
|
||||
"minA": 100,
|
||||
"maxA": 1000,
|
||||
"minB": 100,
|
||||
"maxB": 1000,
|
||||
"inputType": "MultipleChoice"
|
||||
},
|
||||
"requiredCorrectAnswers": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"grade": 3,
|
||||
"name": "Svet 5: Kráľovská citadela (Veľké finále)",
|
||||
"description": "Záverečná výzva tretieho ročníka – mix násobilky, delenia a veľkých čísel!",
|
||||
"background": "assets/images/backgrounds/title_screen_bg.jpg",
|
||||
"levels": [
|
||||
{
|
||||
"id": "3-5-1",
|
||||
"levelNumber": 1,
|
||||
"name": "Elitný Goblin",
|
||||
"enemy": {
|
||||
"id": "elite_guard_goblin",
|
||||
"name": "Elitný Goblin",
|
||||
"maxHp": 50,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/goblin"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["*", "/"],
|
||||
"factors": [2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 5
|
||||
},
|
||||
{
|
||||
"id": "3-5-2",
|
||||
"levelNumber": 2,
|
||||
"name": "Magický Plazmový Sliz",
|
||||
"enemy": {
|
||||
"id": "plasma_slime_boss",
|
||||
"name": "Magický Plazmový Sliz",
|
||||
"maxHp": 65,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/slime"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-", "*", "/"],
|
||||
"minA": 10,
|
||||
"maxA": 100,
|
||||
"minB": 5,
|
||||
"maxB": 50,
|
||||
"maxSum": 200,
|
||||
"factors": [2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 6
|
||||
},
|
||||
{
|
||||
"id": "3-5-3",
|
||||
"levelNumber": 3,
|
||||
"name": "Arcimág Čísel (Záverečný Boss)",
|
||||
"isBoss": true,
|
||||
"enemy": {
|
||||
"id": "archmage_golem_final_boss",
|
||||
"name": "Arcimág Čísel",
|
||||
"maxHp": 85,
|
||||
"attackPower": 1,
|
||||
"assetFolder": "assets/images/enemies/golem"
|
||||
},
|
||||
"mathConfig": {
|
||||
"operations": ["+", "-", "*", "/"],
|
||||
"minA": 10,
|
||||
"maxA": 500,
|
||||
"minB": 10,
|
||||
"maxB": 200,
|
||||
"maxSum": 1000,
|
||||
"factors": [2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
"minMultiplier": 1,
|
||||
"maxMultiplier": 10,
|
||||
"inputType": "DirectInput"
|
||||
},
|
||||
"requiredCorrectAnswers": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="preload" id="webassembly" />
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
<link href="CiselnaVyprava.styles.css" rel="stylesheet" />
|
||||
|
||||
|
||||
<script type="importmap"></script>
|
||||
</head>
|
||||
@@ -38,8 +36,9 @@
|
||||
<a href="." class="reload">Obnoviť hru</a>
|
||||
<span class="dismiss">🗙</span>
|
||||
</div>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
@@ -59,21 +59,15 @@
|
||||
<mimeMap fileExtension=".wav" mimeType="audio/wav" />
|
||||
</staticContent>
|
||||
|
||||
<!-- URL Rewrite for Single Page Application (SPA routing) -->
|
||||
<!-- SPA URL Rewrite -->
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Direct-File-Access" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" />
|
||||
</conditions>
|
||||
<action type="None" />
|
||||
</rule>
|
||||
<rule name="SPA-Routing-Fallback" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||
<add input="{REQUEST_URI}" pattern="^/(_framework|assets|css|data)/" negate="true" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="/" />
|
||||
</rule>
|
||||
|
||||