import React, { useState, useEffect, useRef } from 'react'; import { Castle, Wheat, Trees, Hammer, Coins, Shield, Sword, Crown, Users, Map, Zap, Star, X, ChevronUp, Flame, Skull, Home } from 'lucide-react'; const TotalBattlePrototype = () => { // ============ GAME STATE ============ const [resources, setResources] = useState({ food: 500, wood: 500, stone: 200, gold: 100, }); const [power, setPower] = useState(0); const [view, setView] = useState('castle'); // castle, world, troops, hero const [selectedBuilding, setSelectedBuilding] = useState(null); const [selectedMonster, setSelectedMonster] = useState(null); const [notification, setNotification] = useState(null); const [marches, setMarches] = useState([]); // active army marches const [battleResult, setBattleResult] = useState(null); // Buildings โ each has a level. Production buildings generate resources/hour. const [buildings, setBuildings] = useState({ castle: { level: 1, name: 'Castle', icon: 'castle', upgrading: null }, farm: { level: 1, name: 'Farm', icon: 'wheat', upgrading: null }, lumbermill: { level: 1, name: 'Lumber Mill', icon: 'trees', upgrading: null }, quarry: { level: 1, name: 'Quarry', icon: 'hammer', upgrading: null }, treasury: { level: 1, name: 'Treasury', icon: 'coins', upgrading: null }, barracks: { level: 1, name: 'Barracks', icon: 'sword', upgrading: null }, wall: { level: 1, name: 'Wall', icon: 'shield', upgrading: null }, academy: { level: 0, name: 'Academy', icon: 'star', upgrading: null }, }); // Troops in your barracks const [troops, setTroops] = useState({ swordsmen: 10, archers: 5, cavalry: 0, }); const [training, setTraining] = useState(null); // {type, count, finishesAt} // Hero const [hero, setHero] = useState({ name: 'Aydae', level: 1, xp: 0, attack: 10, defense: 8, }); // World map monsters โ randomly generated const [monsters, setMonsters] = useState(() => generateMonsters()); function generateMonsters() { const types = [ { name: 'Goblin Camp', level: 1, hp: 50, attack: 8, defense: 5, reward: { food: 100, wood: 50, gold: 20, xp: 20 } }, { name: 'Bandit Hideout', level: 2, hp: 120, attack: 15, defense: 10, reward: { food: 200, wood: 100, stone: 50, gold: 50, xp: 50 } }, { name: 'Orc Warband', level: 3, hp: 250, attack: 25, defense: 18, reward: { food: 400, wood: 200, stone: 100, gold: 100, xp: 100 } }, { name: 'Troll Lair', level: 4, hp: 500, attack: 40, defense: 30, reward: { food: 800, wood: 400, stone: 250, gold: 200, xp: 200 } }, { name: 'Dragon Roost', level: 5, hp: 1000, attack: 70, defense: 50, reward: { food: 1500, wood: 800, stone: 500, gold: 500, xp: 500 } }, ]; const out = []; for (let i = 0; i < 12; i++) { const t = types[Math.floor(Math.random() * types.length)]; out.push({ id: i, ...t, currentHp: t.hp, x: 10 + Math.random() * 80, y: 10 + Math.random() * 80, }); } return out; } // ============ TROOP DEFINITIONS ============ const troopTypes = { swordsmen: { name: 'Swordsmen', cost: { food: 20, gold: 5 }, time: 5, attack: 5, defense: 4, hp: 10, icon: 'โ๏ธ' }, archers: { name: 'Archers', cost: { food: 15, wood: 15, gold: 10 }, time: 8, attack: 8, defense: 2, hp: 7, icon: '๐น' }, cavalry: { name: 'Cavalry', cost: { food: 40, wood: 10, gold: 25 }, time: 15, attack: 12, defense: 8, hp: 20, icon: '๐' }, }; // ============ BUILDING DEFINITIONS ============ function buildingCost(key, level) { const targetLevel = level + 1; const base = { castle: { wood: 200, stone: 150, gold: 50 }, farm: { wood: 60, stone: 20 }, lumbermill: { wood: 30, stone: 50 }, quarry: { wood: 80, stone: 30 }, treasury: { wood: 100, stone: 100, gold: 20 }, barracks: { wood: 120, stone: 80, gold: 30 }, wall: { wood: 50, stone: 200 }, academy: { wood: 150, stone: 150, gold: 100 }, }[key]; const cost = {}; Object.entries(base).forEach(([k, v]) => { cost[k] = Math.floor(v * Math.pow(1.5, targetLevel - 1)); }); return cost; } function buildingTime(level) { return 5 + level * 5; // seconds for prototype speed } function buildingProduction(key, level) { if (level === 0) return 0; const base = { farm: 60, lumbermill: 50, quarry: 30, treasury: 20 }; return Math.floor((base[key] || 0) * Math.pow(1.3, level - 1)); } function getResourceType(buildingKey) { return { farm: 'food', lumbermill: 'wood', quarry: 'stone', treasury: 'gold' }[buildingKey]; } // ============ POWER CALCULATION ============ useEffect(() => { let p = 0; Object.values(buildings).forEach(b => { p += b.level * 100; }); Object.entries(troops).forEach(([k, v]) => { const t = troopTypes[k]; p += v * (t.attack + t.defense + t.hp); }); p += hero.level * 50 + hero.attack * 5 + hero.defense * 5; setPower(p); }, [buildings, troops, hero]); // ============ RESOURCE GENERATION TICK ============ useEffect(() => { const interval = setInterval(() => { setResources(prev => { const next = { ...prev }; Object.entries(buildings).forEach(([key, b]) => { const r = getResourceType(key); if (r) { const perSecond = buildingProduction(key, b.level) / 60; next[r] = Math.floor(next[r] + perSecond); } }); return next; }); }, 1000); return () => clearInterval(interval); }, [buildings]); // ============ BUILDING UPGRADE TICK ============ useEffect(() => { const interval = setInterval(() => { setBuildings(prev => { let changed = false; const next = { ...prev }; Object.entries(prev).forEach(([key, b]) => { if (b.upgrading && Date.now() >= b.upgrading) { next[key] = { ...b, level: b.level + 1, upgrading: null }; changed = true; showNotification(`${b.name} upgraded to level ${b.level + 1}!`, 'success'); } }); return changed ? next : prev; }); }, 500); return () => clearInterval(interval); }, []); // ============ TRAINING TICK ============ useEffect(() => { if (!training) return; const interval = setInterval(() => { if (Date.now() >= training.finishesAt) { setTroops(prev => ({ ...prev, [training.type]: prev[training.type] + training.count })); showNotification(`${training.count} ${troopTypes[training.type].name} trained!`, 'success'); setTraining(null); } }, 500); return () => clearInterval(interval); }, [training]); // ============ MARCH/BATTLE TICK ============ useEffect(() => { const interval = setInterval(() => { setMarches(prev => { const remaining = []; const now = Date.now(); prev.forEach(m => { if (now >= m.returnAt) { // Battle complete applyBattleResult(m); } else { remaining.push(m); } }); return remaining; }); }, 500); return () => clearInterval(interval); }, []); function applyBattleResult(march) { const monster = monsters.find(m => m.id === march.monsterId); if (!monster) return; // Calculate army stats let totalAttack = 0, totalDefense = 0, totalHp = 0; Object.entries(march.army).forEach(([k, v]) => { const t = troopTypes[k]; totalAttack += v * t.attack; totalDefense += v * t.defense; totalHp += v * t.hp; }); totalAttack += hero.attack * 10; totalDefense += hero.defense * 10; // Simple battle: if your attack vs monster defense const yourPower = totalAttack + totalHp / 2; const monsterPower = monster.attack * 5 + monster.hp + monster.defense * 3; const won = yourPower > monsterPower; // Losses scale based on how close the battle was const ratio = monsterPower / yourPower; const lossRate = won ? Math.min(0.4, ratio * 0.3) : Math.min(0.95, ratio * 0.7); const survivingArmy = {}; let lostCount = 0; Object.entries(march.army).forEach(([k, v]) => { const survived = Math.floor(v * (1 - lossRate)); survivingArmy[k] = survived; lostCount += v - survived; }); setTroops(prev => { const next = { ...prev }; Object.entries(survivingArmy).forEach(([k, v]) => { next[k] += v; }); return next; }); if (won) { setResources(prev => ({ food: prev.food + monster.reward.food, wood: prev.wood + monster.reward.wood, stone: prev.stone + (monster.reward.stone || 0), gold: prev.gold + monster.reward.gold, })); // Hero XP setHero(prev => { let newXp = prev.xp + monster.reward.xp; let newLevel = prev.level; let newAtk = prev.attack; let newDef = prev.defense; const xpNeeded = newLevel * 100; if (newXp >= xpNeeded) { newXp -= xpNeeded; newLevel++; newAtk += 3; newDef += 2; showNotification(`${prev.name} reached level ${newLevel}!`, 'levelup'); } return { ...prev, xp: newXp, level: newLevel, attack: newAtk, defense: newDef }; }); // Remove monster, spawn a new one setMonsters(prev => { const filtered = prev.filter(m => m.id !== monster.id); const types = [ { name: 'Goblin Camp', level: 1, hp: 50, attack: 8, defense: 5, reward: { food: 100, wood: 50, gold: 20, xp: 20 } }, { name: 'Bandit Hideout', level: 2, hp: 120, attack: 15, defense: 10, reward: { food: 200, wood: 100, stone: 50, gold: 50, xp: 50 } }, { name: 'Orc Warband', level: 3, hp: 250, attack: 25, defense: 18, reward: { food: 400, wood: 200, stone: 100, gold: 100, xp: 100 } }, { name: 'Troll Lair', level: 4, hp: 500, attack: 40, defense: 30, reward: { food: 800, wood: 400, stone: 250, gold: 200, xp: 200 } }, { name: 'Dragon Roost', level: 5, hp: 1000, attack: 70, defense: 50, reward: { food: 1500, wood: 800, stone: 500, gold: 500, xp: 500 } }, ]; const t = types[Math.floor(Math.random() * types.length)]; return [...filtered, { id: Date.now(), ...t, currentHp: t.hp, x: 10 + Math.random() * 80, y: 10 + Math.random() * 80, }]; }); } setBattleResult({ won, monsterName: monster.name, reward: won ? monster.reward : null, lostCount, survivingArmy, }); } // ============ ACTIONS ============ function showNotification(text, type = 'info') { setNotification({ text, type }); setTimeout(() => setNotification(null), 3000); } function canAfford(cost) { return Object.entries(cost).every(([k, v]) => resources[k] >= v); } function payCost(cost) { setResources(prev => { const next = { ...prev }; Object.entries(cost).forEach(([k, v]) => { next[k] -= v; }); return next; }); } function upgradeBuilding(key) { const b = buildings[key]; if (b.upgrading) return; if (key !== 'castle' && b.level >= buildings.castle.level) { showNotification('Upgrade your Castle first!', 'error'); return; } const cost = buildingCost(key, b.level); if (!canAfford(cost)) { showNotification('Not enough resources!', 'error'); return; } payCost(cost); setBuildings(prev => ({ ...prev, [key]: { ...prev[key], upgrading: Date.now() + buildingTime(b.level) * 1000 }, })); showNotification(`Started upgrading ${b.name}...`, 'info'); } function trainTroops(type, count) { if (training) { showNotification('Already training troops!', 'error'); return; } const t = troopTypes[type]; const totalCost = {}; Object.entries(t.cost).forEach(([k, v]) => { totalCost[k] = v * count; }); if (!canAfford(totalCost)) { showNotification('Not enough resources!', 'error'); return; } payCost(totalCost); setTraining({ type, count, finishesAt: Date.now() + t.time * count * 1000 }); showNotification(`Training ${count} ${t.name}...`, 'info'); } function attackMonster(monster, armyComposition) { // Check totals const total = Object.values(armyComposition).reduce((a, b) => a + b, 0); if (total === 0) { showNotification('Send at least one troop!', 'error'); return; } // Verify we have the troops for (const [k, v] of Object.entries(armyComposition)) { if (troops[k] < v) { showNotification('Not enough troops!', 'error'); return; } } // Deduct troops (they're now marching) setTroops(prev => { const next = { ...prev }; Object.entries(armyComposition).forEach(([k, v]) => { next[k] -= v; }); return next; }); // Travel time based on monster level const travelTime = (5 + monster.level * 3) * 1000; setMarches(prev => [...prev, { id: Date.now(), monsterId: monster.id, monsterName: monster.name, army: armyComposition, returnAt: Date.now() + travelTime, totalTime: travelTime, startedAt: Date.now(), }]); setSelectedMonster(null); showNotification(`Army marching to ${monster.name}...`, 'info'); } // ============ UI HELPERS ============ function ResourceBar() { return (
Level {b.level}
Level {m.level}
vs {r.monsterName}
{r.won && r.reward && (