mount-and-blade / index.html
yazdaabdul's picture
undefined - Initial Deployment
fc18878 verified
raw
history blame
52 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mount & Blade: German Wars 1400</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.map-container {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Holy_Roman_Empire_1400.svg/1200px-Holy_Roman_Empire_1400.svg.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
position: relative;
height: 70vh;
}
.settlement {
position: absolute;
width: 20px;
height: 20px;
border-radius: 50%;
cursor: pointer;
transition: all 0.3s;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: white;
text-shadow: 1px 1px 2px black;
}
.settlement:hover {
transform: scale(1.5);
z-index: 10;
}
.castle {
background-color: #8B4513;
}
.town {
background-color: #4682B4;
}
.village {
background-color: #228B22;
}
.battle-animation {
animation: pulse 1s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.faction-bavaria { background-color: #000080; }
.faction-swabia { background-color: #FF0000; }
.faction-franconia { background-color: #FFD700; }
.faction-saxony { background-color: #008000; }
.faction-lorraine { background-color: #FFFFFF; border: 1px solid #000; }
.faction-player { background-color: #800080; }
.tooltip {
position: absolute;
background-color: rgba(0, 0, 0, 0.8);
color: white;
padding: 5px 10px;
border-radius: 5px;
pointer-events: none;
z-index: 100;
font-size: 14px;
max-width: 200px;
}
.combat-log {
height: 200px;
overflow-y: auto;
background-color: #1a1a1a;
color: #e0e0e0;
padding: 10px;
border-radius: 5px;
font-family: monospace;
}
.combat-entry {
margin-bottom: 5px;
border-bottom: 1px solid #333;
padding-bottom: 3px;
}
.victory { color: #4CAF50; }
.defeat { color: #F44336; }
.neutral { color: #FFC107; }
</style>
</head>
<body class="bg-gray-900 text-white">
<div class="container mx-auto px-4 py-8">
<header class="mb-8 text-center">
<h1 class="text-4xl font-bold mb-2 text-yellow-400">Mount & Blade: German Wars 1400</h1>
<p class="text-lg text-gray-300">Lead your faction to dominance in the fractured Holy Roman Empire</p>
</header>
<div id="game-container">
<!-- Character Creation Screen -->
<div id="character-creation" class="bg-gray-800 p-6 rounded-lg shadow-lg max-w-2xl mx-auto">
<h2 class="text-2xl font-bold mb-6 text-center text-yellow-400">Create Your Character</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<div class="mb-4">
<label class="block text-gray-300 mb-2">Character Name</label>
<input type="text" id="char-name" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded" value="Sir Ulrich">
</div>
<div class="mb-4">
<label class="block text-gray-300 mb-2">Faction</label>
<select id="faction-select" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded">
<option value="bavaria">Duchy of Bavaria (Blue)</option>
<option value="swabia">Duchy of Swabia (Red)</option>
<option value="franconia">Duchy of Franconia (Gold)</option>
<option value="saxony">Duchy of Saxony (Green)</option>
<option value="lorraine">Duchy of Lorraine (White)</option>
</select>
</div>
<div class="mb-4">
<label class="block text-gray-300 mb-2">Background</label>
<select id="background-select" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded">
<option value="noble">Noble Son (+Leadership, +Relations with Nobles)</option>
<option value="merchant">Merchant (+Trade, +Gold)</option>
<option value="mercenary">Mercenary (+Combat Skills, -Relations with Nobles)</option>
<option value="peasant">Peasant (+Recruitment, -Starting Gold)</option>
</select>
</div>
</div>
<div>
<div class="mb-4">
<label class="block text-gray-300 mb-2">Starting Location</label>
<select id="start-location" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded">
<option value="munich">Munich (Bavaria)</option>
<option value="augsburg">Augsburg (Swabia)</option>
<option value="wurzburg">Würzburg (Franconia)</option>
<option value="leipzig">Leipzig (Saxony)</option>
<option value="trier">Trier (Lorraine)</option>
</select>
</div>
<div class="mb-4">
<label class="block text-gray-300 mb-2">Difficulty</label>
<select id="difficulty" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded">
<option value="easy">Easy (More gold, weaker enemies)</option>
<option value="normal" selected>Normal (Balanced experience)</option>
<option value="hard">Hard (Less gold, stronger enemies)</option>
</select>
</div>
</div>
</div>
<div class="mt-6 text-center">
<button id="start-game" class="px-6 py-3 bg-yellow-600 hover:bg-yellow-700 rounded-lg font-bold transition">Begin Your Adventure</button>
</div>
</div>
<!-- Main Game Screen (initially hidden) -->
<div id="game-screen" class="hidden">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-6">
<!-- Player Stats Panel -->
<div class="bg-gray-800 p-4 rounded-lg shadow">
<h3 class="text-xl font-bold mb-4 border-b border-gray-700 pb-2">Player Info</h3>
<div class="space-y-3">
<div>
<span class="font-semibold">Name:</span> <span id="player-name">Sir Ulrich</span>
</div>
<div>
<span class="font-semibold">Faction:</span> <span id="player-faction">Bavaria</span>
</div>
<div>
<span class="font-semibold">Gold:</span> <span id="player-gold">1000</span> <i class="fas fa-coins text-yellow-400"></i>
</div>
<div>
<span class="font-semibold">Renown:</span> <span id="player-renown">0</span>
</div>
<div>
<span class="font-semibold">Troops:</span> <span id="player-troops">0/50</span>
</div>
<div class="pt-2">
<div class="w-full bg-gray-700 rounded-full h-2.5">
<div id="health-bar" class="bg-red-600 h-2.5 rounded-full" style="width: 100%"></div>
</div>
<span class="text-sm">Health: <span id="health-text">100</span>/100</span>
</div>
</div>
</div>
<!-- Current Location Panel -->
<div class="bg-gray-800 p-4 rounded-lg shadow">
<h3 class="text-xl font-bold mb-4 border-b border-gray-700 pb-2">Current Location</h3>
<div id="location-info" class="space-y-3">
<div class="text-center py-8 text-gray-500">
Select a settlement on the map
</div>
</div>
</div>
<!-- Actions Panel -->
<div class="bg-gray-800 p-4 rounded-lg shadow">
<h3 class="text-xl font-bold mb-4 border-b border-gray-700 pb-2">Actions</h3>
<div id="action-buttons" class="space-y-2">
<button class="action-btn w-full px-4 py-2 bg-blue-700 hover:bg-blue-800 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-swords mr-2"></i> Attack
</button>
<button class="action-btn w-full px-4 py-2 bg-green-700 hover:bg-green-800 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-handshake mr-2"></i> Negotiate
</button>
<button class="action-btn w-full px-4 py-2 bg-yellow-700 hover:bg-yellow-800 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-users mr-2"></i> Recruit
</button>
<button class="action-btn w-full px-4 py-2 bg-purple-700 hover:bg-purple-800 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-store mr-2"></i> Trade
</button>
<button class="action-btn w-full px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-route mr-2"></i> Travel
</button>
</div>
</div>
<!-- Game Log -->
<div class="bg-gray-800 p-4 rounded-lg shadow">
<h3 class="text-xl font-bold mb-4 border-b border-gray-700 pb-2">Game Log</h3>
<div id="game-log" class="h-48 overflow-y-auto text-sm space-y-1">
<div class="text-gray-400 italic">Game begins...</div>
</div>
</div>
</div>
<!-- Map and Combat Area -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Map Container -->
<div class="lg:col-span-2 bg-gray-800 p-4 rounded-lg shadow">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold">Holy Roman Empire - 1400 AD</h3>
<div class="flex space-x-2">
<button id="end-turn" class="px-4 py-2 bg-red-700 hover:bg-red-800 rounded">
<i class="fas fa-hourglass-end mr-2"></i> End Turn
</button>
</div>
</div>
<div class="map-container rounded-lg border border-gray-700 relative" id="game-map">
<!-- Settlements will be added here by JavaScript -->
<div class="tooltip hidden" id="map-tooltip"></div>
</div>
<div class="mt-4 grid grid-cols-2 md:grid-cols-5 gap-2">
<div class="flex items-center">
<div class="w-4 h-4 rounded-full bg-blue-500 mr-2"></div>
<span>Bavaria</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 rounded-full bg-red-500 mr-2"></div>
<span>Swabia</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 rounded-full bg-yellow-500 mr-2"></div>
<span>Franconia</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 rounded-full bg-green-500 mr-2"></div>
<span>Saxony</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 rounded-full bg-white border border-gray-500 mr-2"></div>
<span>Lorraine</span>
</div>
</div>
</div>
<!-- Combat/Event Panel -->
<div class="bg-gray-800 p-4 rounded-lg shadow">
<h3 class="text-xl font-bold mb-4 border-b border-gray-700 pb-2" id="combat-header">Events</h3>
<div id="combat-screen" class="hidden">
<div class="flex justify-between items-center mb-4">
<div>
<span class="font-semibold">Player:</span> <span id="combat-player">Sir Ulrich</span>
</div>
<div>
<span class="font-semibold">vs</span>
</div>
<div>
<span class="font-semibold">Enemy:</span> <span id="combat-enemy">Bandits</span>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<div class="text-center font-semibold mb-1">Player Forces</div>
<div id="player-forces" class="bg-gray-700 p-2 rounded">
<!-- Will be filled by JS -->
</div>
</div>
<div>
<div class="text-center font-semibold mb-1">Enemy Forces</div>
<div id="enemy-forces" class="bg-gray-700 p-2 rounded">
<!-- Will be filled by JS -->
</div>
</div>
</div>
<div class="mb-4">
<div class="combat-log" id="combat-log">
<!-- Combat messages will appear here -->
</div>
</div>
<div class="flex space-x-2">
<button id="attack-btn" class="flex-1 px-4 py-2 bg-red-700 hover:bg-red-800 rounded">
<i class="fas fa-swords mr-2"></i> Attack
</button>
<button id="retreat-btn" class="flex-1 px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded">
<i class="fas fa-running mr-2"></i> Retreat
</button>
</div>
</div>
<div id="event-screen">
<div class="text-center py-8 text-gray-500">
No current events
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Game State
const gameState = {
player: {
name: "Sir Ulrich",
faction: "bavaria",
gold: 1000,
renown: 0,
maxTroops: 50,
currentTroops: 0,
health: 100,
maxHealth: 100,
location: null,
background: "noble",
relations: {
bavaria: 50,
swabia: 0,
franconia: 0,
saxony: 0,
lorraine: 0
},
inventory: {
food: 50,
weapons: 20,
armor: 10
}
},
factions: {
bavaria: { name: "Bavaria", color: "blue", strength: 70, relations: {} },
swabia: { name: "Swabia", color: "red", strength: 60, relations: {} },
franconia: { name: "Franconia", color: "yellow", strength: 55, relations: {} },
saxony: { name: "Saxony", color: "green", strength: 65, relations: {} },
lorraine: { name: "Lorraine", color: "white", strength: 50, relations: {} }
},
settlements: [
{ id: "munich", name: "Munich", type: "town", faction: "bavaria", x: 75, y: 85, garrison: 150, wealth: 800 },
{ id: "augsburg", name: "Augsburg", type: "town", faction: "swabia", x: 60, y: 70, garrison: 120, wealth: 700 },
{ id: "nuremberg", name: "Nuremberg", type: "town", faction: "franconia", x: 50, y: 60, garrison: 100, wealth: 750 },
{ id: "wurzburg", name: "Würzburg", type: "town", faction: "franconia", x: 40, y: 55, garrison: 90, wealth: 600 },
{ id: "frankfurt", name: "Frankfurt", type: "town", faction: "franconia", x: 30, y: 50, garrison: 110, wealth: 850 },
{ id: "leipzig", name: "Leipzig", type: "town", faction: "saxony", x: 65, y: 40, garrison: 95, wealth: 650 },
{ id: "trier", name: "Trier", type: "town", faction: "lorraine", x: 15, y: 60, garrison: 80, wealth: 550 },
{ id: "regensburg", name: "Regensburg", type: "castle", faction: "bavaria", x: 80, y: 75, garrison: 70, wealth: 400 },
{ id: "ulm", name: "Ulm", type: "castle", faction: "swabia", x: 55, y: 65, garrison: 60, wealth: 350 },
{ id: "bamberg", name: "Bamberg", type: "castle", faction: "franconia", x: 45, y: 58, garrison: 50, wealth: 300 },
{ id: "erfurt", name: "Erfurt", type: "castle", faction: "saxony", x: 55, y: 45, garrison: 55, wealth: 320 },
{ id: "mainz", name: "Mainz", type: "castle", faction: "lorraine", x: 25, y: 55, garrison: 45, wealth: 280 },
{ id: "village1", name: "Dorf an der Donau", type: "village", faction: "bavaria", x: 70, y: 80, garrison: 10, wealth: 150 },
{ id: "village2", name: "Schwäbisches Dorf", type: "village", faction: "swabia", x: 58, y: 68, garrison: 8, wealth: 120 },
{ id: "village3", name: "Fränkisches Dorf", type: "village", faction: "franconia", x: 48, y: 62, garrison: 7, wealth: 110 },
{ id: "village4", name: "Sächsisches Dorf", type: "village", faction: "saxony", x: 60, y: 42, garrison: 9, wealth: 130 },
{ id: "village5", name: "Lothringisches Dorf", type: "village", faction: "lorraine", x: 20, y: 58, garrison: 6, wealth: 100 }
],
currentTurn: 1,
inCombat: false,
combatEnemy: null,
selectedSettlement: null,
gameLog: []
};
// DOM Elements
const characterCreation = document.getElementById('character-creation');
const gameScreen = document.getElementById('game-screen');
const startGameBtn = document.getElementById('start-game');
const playerNameEl = document.getElementById('player-name');
const playerFactionEl = document.getElementById('player-faction');
const playerGoldEl = document.getElementById('player-gold');
const playerRenownEl = document.getElementById('player-renown');
const playerTroopsEl = document.getElementById('player-troops');
const healthBarEl = document.getElementById('health-bar');
const healthTextEl = document.getElementById('health-text');
const gameMap = document.getElementById('game-map');
const locationInfo = document.getElementById('location-info');
const actionButtons = document.querySelectorAll('.action-btn');
const gameLog = document.getElementById('game-log');
const combatScreen = document.getElementById('combat-screen');
const combatHeader = document.getElementById('combat-header');
const combatPlayerEl = document.getElementById('combat-player');
const combatEnemyEl = document.getElementById('combat-enemy');
const playerForcesEl = document.getElementById('player-forces');
const enemyForcesEl = document.getElementById('enemy-forces');
const combatLogEl = document.getElementById('combat-log');
const attackBtn = document.getElementById('attack-btn');
const retreatBtn = document.getElementById('retreat-btn');
const endTurnBtn = document.getElementById('end-turn');
const mapTooltip = document.getElementById('map-tooltip');
// Initialize game
function initGame() {
// Set up event listeners
startGameBtn.addEventListener('click', startGame);
endTurnBtn.addEventListener('click', endTurn);
attackBtn.addEventListener('click', combatAttack);
retreatBtn.addEventListener('click', combatRetreat);
// Create settlements on map
renderSettlements();
// Set up settlement click handlers
document.querySelectorAll('.settlement').forEach(settlement => {
settlement.addEventListener('click', () => selectSettlement(settlement.dataset.id));
settlement.addEventListener('mouseenter', showSettlementTooltip);
settlement.addEventListener('mouseleave', hideSettlementTooltip);
});
// Set up action buttons
document.querySelectorAll('.action-btn').forEach((btn, index) => {
btn.addEventListener('click', () => handleAction(index));
});
}
// Start the game
function startGame() {
// Get character creation values
gameState.player.name = document.getElementById('char-name').value || "Sir Ulrich";
gameState.player.faction = document.getElementById('faction-select').value;
gameState.player.background = document.getElementById('background-select').value;
const startLocation = document.getElementById('start-location').value;
const difficulty = document.getElementById('difficulty').value;
// Apply background bonuses
applyBackgroundBonuses();
// Apply difficulty settings
applyDifficultySettings(difficulty);
// Set starting location
const startingSettlement = gameState.settlements.find(s => s.id === startLocation);
gameState.player.location = startingSettlement.id;
// Update UI
updatePlayerInfo();
selectSettlement(startLocation);
// Switch to game screen
characterCreation.classList.add('hidden');
gameScreen.classList.remove('hidden');
// Add starting troops
recruitTroops(10);
// Add initial log entry
addGameLog(`You begin your journey in ${startingSettlement.name} as a noble of ${gameState.factions[gameState.player.faction].name}.`);
}
function applyBackgroundBonuses() {
switch(gameState.player.background) {
case 'noble':
gameState.player.renown = 20;
for (const faction in gameState.player.relations) {
if (faction !== gameState.player.faction) {
gameState.player.relations[faction] = -10;
} else {
gameState.player.relations[faction] = 50;
}
}
break;
case 'merchant':
gameState.player.gold = 1500;
gameState.player.inventory.food = 100;
break;
case 'mercenary':
gameState.player.maxTroops = 70;
gameState.player.currentTroops = 20;
for (const faction in gameState.player.relations) {
gameState.player.relations[faction] = -20;
}
break;
case 'peasant':
gameState.player.gold = 500;
gameState.player.maxTroops = 80;
gameState.player.currentTroops = 15;
gameState.player.relations[gameState.player.faction] = 30;
break;
}
}
function applyDifficultySettings(difficulty) {
switch(difficulty) {
case 'easy':
gameState.player.gold *= 1.5;
gameState.player.maxHealth *= 1.2;
gameState.player.health = gameState.player.maxHealth;
break;
case 'hard':
gameState.player.gold *= 0.7;
gameState.player.maxHealth *= 0.8;
gameState.player.health = gameState.player.maxHealth;
break;
}
}
// Render settlements on the map
function renderSettlements() {
gameState.settlements.forEach(settlement => {
const settlementEl = document.createElement('div');
settlementEl.className = `settlement ${settlement.type} faction-${settlement.faction}`;
settlementEl.dataset.id = settlement.id;
settlementEl.style.left = `${settlement.x}%`;
settlementEl.style.top = `${settlement.y}%`;
// Add first letter of settlement name as marker
const letter = document.createElement('span');
letter.textContent = settlement.name.charAt(0);
settlementEl.appendChild(letter);
gameMap.appendChild(settlementEl);
});
}
// Show settlement tooltip
function showSettlementTooltip(e) {
const settlementId = e.currentTarget.dataset.id;
const settlement = gameState.settlements.find(s => s.id === settlementId);
mapTooltip.innerHTML = `
<div class="font-bold">${settlement.name}</div>
<div>Type: ${settlement.type.charAt(0).toUpperCase() + settlement.type.slice(1)}</div>
<div>Faction: ${gameState.factions[settlement.faction].name}</div>
<div>Garrison: ${settlement.garrison}</div>
<div>Wealth: ${settlement.wealth}</div>
`;
mapTooltip.style.left = `${e.pageX + 10}px`;
mapTooltip.style.top = `${e.pageY + 10}px`;
mapTooltip.classList.remove('hidden');
}
// Hide settlement tooltip
function hideSettlementTooltip() {
mapTooltip.classList.add('hidden');
}
// Select a settlement
function selectSettlement(settlementId) {
const settlement = gameState.settlements.find(s => s.id === settlementId);
gameState.selectedSettlement = settlement;
// Update location info
locationInfo.innerHTML = `
<div class="text-center font-bold text-lg mb-2">${settlement.name}</div>
<div class="grid grid-cols-2 gap-2 mb-3">
<div><span class="font-semibold">Type:</span> ${settlement.type.charAt(0).toUpperCase() + settlement.type.slice(1)}</div>
<div><span class="font-semibold">Faction:</span> ${gameState.factions[settlement.faction].name}</div>
<div><span class="font-semibold">Garrison:</span> ${settlement.garrison}</div>
<div><span class="font-semibold">Wealth:</span> ${settlement.wealth}</div>
</div>
<div class="text-sm text-gray-400 italic">
${getSettlementDescription(settlement)}
</div>
`;
// Enable/disable action buttons based on settlement
actionButtons.forEach(btn => btn.disabled = false);
// Special cases
if (settlement.faction === gameState.player.faction) {
document.querySelectorAll('.action-btn')[1].disabled = true; // Disable negotiate with own faction
}
if (settlement.id === gameState.player.location) {
document.querySelectorAll('.action-btn')[4].disabled = true; // Disable travel to current location
}
// Highlight selected settlement on map
document.querySelectorAll('.settlement').forEach(el => {
el.classList.remove('border-2', 'border-white');
});
document.querySelector(`.settlement[data-id="${settlementId}"]`).classList.add('border-2', 'border-white');
}
function getSettlementDescription(settlement) {
const faction = gameState.factions[settlement.faction];
const playerFaction = gameState.factions[gameState.player.faction];
if (settlement.type === 'town') {
return `A bustling ${faction.name} town with merchants, craftsmen, and a strong garrison.`;
} else if (settlement.type === 'castle') {
return `A formidable ${faction.name} castle, home to local nobility and their retinue.`;
} else {
return `A quiet ${faction.name} village, where peasants work the land.`;
}
}
// Handle action button clicks
function handleAction(actionIndex) {
const settlement = gameState.selectedSettlement;
switch(actionIndex) {
case 0: // Attack
if (settlement.faction === gameState.player.faction) {
addGameLog("You cannot attack your own faction's settlements!");
return;
}
if (gameState.player.currentTroops < 5) {
addGameLog("You need at least 5 troops to attack!");
return;
}
startCombat(settlement);
break;
case 1: // Negotiate
if (settlement.faction === gameState.player.faction) {
return;
}
negotiate(settlement);
break;
case 2: // Recruit
recruitTroops(5);
break;
case 3: // Trade
trade();
break;
case 4: // Travel
travelTo(settlement);
break;
}
}
// Start combat with a settlement
function startCombat(settlement) {
gameState.inCombat = true;
gameState.combatEnemy = {
name: `${settlement.name} Garrison`,
type: 'garrison',
troops: Math.floor(settlement.garrison * 0.7), // Only part of garrison fights
health: 100
};
// Update combat UI
combatHeader.textContent = "Battle";
combatPlayerEl.textContent = gameState.player.name;
combatEnemyEl.textContent = gameState.combatEnemy.name;
// Show forces
updateCombatForces();
// Clear combat log
combatLogEl.innerHTML = '';
// Show combat screen
combatScreen.classList.remove('hidden');
// Add initial log
addCombatLog(`You engage the ${settlement.name} garrison in battle!`, 'neutral');
}
// Update combat forces display
function updateCombatForces() {
playerForcesEl.innerHTML = `
<div class="mb-2">
<div class="flex justify-between mb-1">
<span>Troops:</span>
<span>${gameState.player.currentTroops}</span>
</div>
<div class="w-full bg-gray-600 rounded-full h-2">
<div class="bg-blue-600 h-2 rounded-full" style="width: ${gameState.player.health}%"></div>
</div>
</div>
`;
enemyForcesEl.innerHTML = `
<div class="mb-2">
<div class="flex justify-between mb-1">
<span>Troops:</span>
<span>${gameState.combatEnemy.troops}</span>
</div>
<div class="w-full bg-gray-600 rounded-full h-2">
<div class="bg-red-600 h-2 rounded-full" style="width: ${gameState.combatEnemy.health}%"></div>
</div>
</div>
`;
}
// Handle combat attack
function combatAttack() {
if (!gameState.inCombat) return;
// Player attacks
const playerDamage = Math.floor(Math.random() * 20) + 10 + gameState.player.currentTroops;
const enemyDamage = Math.floor(Math.random() * 15) + 5 + gameState.combatEnemy.troops;
// Apply damage
gameState.combatEnemy.health -= playerDamage / 2;
gameState.player.health -= enemyDamage / 2;
// Update troop numbers based on damage
const playerTroopsLost = Math.floor(enemyDamage / 10);
const enemyTroopsLost = Math.floor(playerDamage / 10);
gameState.player.currentTroops = Math.max(0, gameState.player.currentTroops - playerTroopsLost);
gameState.combatEnemy.troops = Math.max(0, gameState.combatEnemy.troops - enemyTroopsLost);
// Update UI
updateCombatForces();
updatePlayerInfo();
// Add combat log
addCombatLog(`Your forces attack! You lose ${playerTroopsLost} troops and deal ${enemyTroopsLost} casualties.`, 'neutral');
// Check for combat end
if (gameState.player.health <= 0 || gameState.player.currentTroops <= 0) {
endCombat(false);
return;
}
if (gameState.combatEnemy.health <= 0 || gameState.combatEnemy.troops <= 0) {
endCombat(true);
return;
}
}
// Handle combat retreat
function combatRetreat() {
if (!gameState.inCombat) return;
// Lose some troops during retreat
const troopsLost = Math.floor(gameState.player.currentTroops * 0.3);
gameState.player.currentTroops -= troopsLost;
// Update UI
updatePlayerInfo();
// Add combat log
addCombatLog(`You retreat from battle, losing ${troopsLost} troops in the process.`, 'defeat');
// End combat
endCombat(false);
}
// End combat
function endCombat(victory) {
gameState.inCombat = false;
if (victory) {
// Calculate loot
const loot = Math.floor(gameState.selectedSettlement.wealth * 0.3);
gameState.player.gold += loot;
gameState.player.renown += 5;
// Update settlement
gameState.selectedSettlement.garrison = Math.floor(gameState.selectedSettlement.garrison * 0.5);
// Update UI
updatePlayerInfo();
addCombatLog(`You are victorious! You gain ${loot} gold and 5 renown.`, 'victory');
addGameLog(`You defeated the ${gameState.selectedSettlement.name} garrison and gained ${loot} gold!`);
} else {
addCombatLog("You were defeated in battle.", 'defeat');
addGameLog("You were defeated in battle.");
// If player has no troops left, they're captured
if (gameState.player.currentTroops <= 0) {
gameState.player.health = 50;
gameState.player.gold = Math.floor(gameState.player.gold * 0.5);
addGameLog("You've been captured! You lose half your gold and are returned to your starting location.");
// Return to starting location
const startingSettlement = gameState.settlements.find(s => s.id === gameState.player.location);
selectSettlement(startingSettlement.id);
}
}
// Hide combat screen after delay
setTimeout(() => {
combatScreen.classList.add('hidden');
}, 3000);
}
// Add message to combat log
function addCombatLog(message, type) {
const entry = document.createElement('div');
entry.className = `combat-entry ${type}`;
entry.textContent = message;
combatLogEl.appendChild(entry);
combatLogEl.scrollTop = combatLogEl.scrollHeight;
}
// Negotiate with settlement
function negotiate(settlement) {
const faction = settlement.faction;
const currentRelation = gameState.player.relations[faction] || 0;
// Can't negotiate if relation is too low
if (currentRelation < -20) {
addGameLog(`The ${gameState.factions[faction].name} refuse to negotiate with you due to poor relations.`);
return;
}
// Chance of success based on relation
const successChance = 50 + currentRelation;
const isSuccess = Math.random() * 100 < successChance;
if (isSuccess) {
// Improve relations
gameState.player.relations[faction] = (gameState.player.relations[faction] || 0) + 5;
// Possible tribute
if (Math.random() > 0.7) {
const tribute = Math.floor(settlement.wealth * 0.1);
gameState.player.gold += tribute;
addGameLog(`Negotiation successful! ${settlement.name} agrees to pay you ${tribute} gold in tribute. Relations with ${gameState.factions[faction].name} improved.`);
} else {
addGameLog(`Negotiation successful! Relations with ${gameState.factions[faction].name} improved.`);
}
} else {
// Small relation penalty for failed negotiation
gameState.player.relations[faction] = (gameState.player.relations[faction] || 0) - 2;
addGameLog(`Negotiation failed. The ${gameState.factions[faction].name} are not interested in your proposals.`);
}
updatePlayerInfo();
}
// Recruit troops
function recruitTroops(amount) {
if (gameState.selectedSettlement.faction !== gameState.player.faction) {
addGameLog("You can only recruit troops in your own faction's settlements!");
return;
}
const costPerTroop = 10;
const totalCost = amount * costPerTroop;
if (gameState.player.gold < totalCost) {
addGameLog(`You need ${totalCost} gold to recruit ${amount} troops!`);
return;
}
if (gameState.player.currentTroops + amount > gameState.player.maxTroops) {
amount = gameState.player.maxTroops - gameState.player.currentTroops;
if (amount <= 0) {
addGameLog("You've reached your maximum troop capacity!");
return;
}
}
gameState.player.gold -= amount * costPerTroop;
gameState.player.currentTroops += amount;
addGameLog(`You recruited ${amount} troops for ${amount * costPerTroop} gold.`);
updatePlayerInfo();
}
// Trade goods
function trade() {
const settlement = gameState.selectedSettlement;
const tradeAmount = 50;
const profit = Math.floor(Math.random() * 30) + 10;
// Can't trade in enemy settlements
if (settlement.faction !== gameState.player.faction) {
addGameLog("You can only trade in your own faction's settlements!");
return;
}
// Need some food to trade
if (gameState.player.inventory.food < tradeAmount) {
addGameLog(`You need at least ${tradeAmount} food to trade!`);
return;
}
gameState.player.inventory.food -= tradeAmount;
gameState.player.gold += profit;
addGameLog(`You traded ${tradeAmount} food and made ${profit} gold profit.`);
updatePlayerInfo();
}
// Travel to a settlement
function travelTo(settlement) {
if (settlement.id === gameState.player.location) {
return;
}
// Random events can happen during travel
const eventRoll = Math.random();
if (eventRoll < 0.3) {
// No event
addGameLog(`You travel safely to ${settlement.name}.`);
} else if (eventRoll < 0.6) {
// Find some loot
const loot = Math.floor(Math.random() * 50) + 20;
gameState.player.gold += loot;
addGameLog(`On the way to ${settlement.name}, you find ${loot} gold!`);
} else if (eventRoll < 0.9) {
// Bandit attack
startRandomCombat();
return; // Don't change location if combat happens
} else {
// Noble encounter
const nobleGift = Math.floor(Math.random() * 100) + 50;
gameState.player.gold += nobleGift;
addGameLog(`You meet a friendly noble on the road who gifts you ${nobleGift} gold!`);
}
// Update location
gameState.player.location = settlement.id;
updatePlayerInfo();
addGameLog(`You arrive at ${settlement.name}.`);
}
// Start random combat (bandits)
function startRandomCombat() {
gameState.inCombat = true;
const banditStrength = Math.floor(gameState.player.currentTroops * (0.5 + Math.random() * 0.5));
gameState.combatEnemy = {
name: "Bandit Group",
type: 'bandits',
troops: banditStrength,
health: 100
};
// Update combat UI
combatHeader.textContent = "Ambush!";
combatPlayerEl.textContent = gameState.player.name;
combatEnemyEl.textContent = gameState.combatEnemy.name;
// Show forces
updateCombatForces();
// Clear combat log
combatLogEl.innerHTML = '';
// Show combat screen
combatScreen.classList.remove('hidden');
// Add initial log
addCombatLog(`You've been ambushed by bandits!`, 'neutral');
addGameLog("Your party has been ambushed by bandits on the road!");
}
// End turn
function endTurn() {
gameState.currentTurn++;
// Pay troop wages
const wages = gameState.player.currentTroops * 2;
gameState.player.gold -= wages;
// Consume food
const foodConsumed = gameState.player.currentTroops;
gameState.player.inventory.food -= foodConsumed;
// Handle negative food (troops desert)
if (gameState.player.inventory.food < 0) {
const deserters = Math.floor(gameState.player.currentTroops * 0.2);
gameState.player.currentTroops -= deserters;
gameState.player.inventory.food = 0;
addGameLog(`${deserters} troops deserted due to lack of food!`);
}
// Handle negative gold (troops desert)
if (gameState.player.gold < 0) {
const deserters = Math.floor(gameState.player.currentTroops * 0.3);
gameState.player.currentTroops -= deserters;
gameState.player.gold = 0;
addGameLog(`${deserters} troops deserted due to lack of pay!`);
}
// Random events
const eventRoll = Math.random();
if (eventRoll < 0.2) {
// Positive event
const positiveEvents = [
{ message: "A group of mercenaries joins your cause!", effect: () => { gameState.player.currentTroops += 5; } },
{ message: "You find a chest of gold on the road!", effect: () => { gameState.player.gold += 100; } },
{ message: "Your reputation grows, attracting more troops.", effect: () => { gameState.player.renown += 3; } }
];
const event = positiveEvents[Math.floor(Math.random() * positiveEvents.length)];
event.effect();
addGameLog(event.message);
} else if (eventRoll < 0.4) {
// Negative event
const negativeEvents = [
{ message: "A disease sweeps through your camp.", effect: () => { gameState.player.currentTroops = Math.floor(gameState.player.currentTroops * 0.9); } },
{ message: "Thieves steal some of your gold!", effect: () => { gameState.player.gold = Math.floor(gameState.player.gold * 0.8); } },
{ message: "A rival spreads rumors about you.", effect: () => { gameState.player.renown -= 3; } }
];
const event = negativeEvents[Math.floor(Math.random() * negativeEvents.length)];
event.effect();
addGameLog(event.message);
}
// Update UI
updatePlayerInfo();
addGameLog(`Turn ${gameState.currentTurn} completed. You paid ${wages} gold in wages and consumed ${foodConsumed} food.`);
}
// Update player info display
function updatePlayerInfo() {
playerNameEl.textContent = gameState.player.name;
playerFactionEl.textContent = gameState.factions[gameState.player.faction].name;
playerGoldEl.textContent = gameState.player.gold;
playerRenownEl.textContent = gameState.player.renown;
playerTroopsEl.textContent = `${gameState.player.currentTroops}/${gameState.player.maxTroops}`;
healthTextEl.textContent = `${gameState.player.health}`;
healthBarEl.style.width = `${gameState.player.health}%`;
}
// Add message to game log
function addGameLog(message) {
const entry = document.createElement('div');
entry.className = 'border-b border-gray-700 pb-1';
entry.textContent = `[Turn ${gameState.currentTurn}] ${message}`;
gameLog.appendChild(entry);
gameLog.scrollTop = gameLog.scrollHeight;
// Keep log to 50 entries max
if (gameLog.children.length > 50) {
gameLog.removeChild(gameLog.children[0]);
}
// Add to game state log
gameState.gameLog.push(message);
}
// Initialize the game when page loads
window.addEventListener('DOMContentLoaded', initGame);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=yazdaabdul/mount-and-blade" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>