✨feature: Split styles and JavaScript to separate files, rework layout
This commit is contained in:
156
index.php
156
index.php
@@ -3,138 +3,25 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Corpus Worker RPG (Web)</title>
|
||||
<style>
|
||||
body { font-family: system-ui, Arial, sans-serif; margin: 0; background:#0f1420; color:#e9eef8; }
|
||||
header { padding: 12px 16px; background: #121a2a; border-bottom: 1px solid #27324a; display:flex; align-items:center; justify-content:space-between; }
|
||||
h1 { margin: 0; font-size: 18px; }
|
||||
main { display: grid; grid-template-columns: 300px 1fr; gap: 16px; padding: 16px; }
|
||||
.panel { background:#111827; border:1px solid #27324a; border-radius:8px; }
|
||||
.panel h2 { font-size:14px; margin: 0; padding: 12px 12px 0; color:#a3b5d9; }
|
||||
.panel .content { padding: 12px; }
|
||||
#log { background:#0b1020; color:#e9eef8; min-height: 360px; max-height: 60vh; overflow: auto; white-space: pre-wrap; }
|
||||
.row { display:flex; gap:8px; flex-wrap:wrap; }
|
||||
button { background:#1f2a44; color:#e9eef8; border:1px solid #2c3a5e; border-radius:6px; padding:8px 10px; cursor:pointer; }
|
||||
button:hover { background:#263356; }
|
||||
button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.muted { color:#a3b5d9; }
|
||||
.sep { height:1px; background:#27324a; margin: 8px 0; }
|
||||
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
||||
.kv { display:flex; justify-content:space-between; gap:8px; margin:2px 0; }
|
||||
.kv .label { color:#a3b5d9; }
|
||||
</style>
|
||||
<script>
|
||||
async function api(action, value) {
|
||||
const res = await fetch('game.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action, value })
|
||||
});
|
||||
if (!res.ok) throw new Error('Network error: ' + res.status);
|
||||
return res.json();
|
||||
}
|
||||
<title>Days In Fortuna</title>
|
||||
|
||||
function appendLog(lines) {
|
||||
const log = document.getElementById('log');
|
||||
const atBottom = Math.abs(log.scrollHeight - log.scrollTop - log.clientHeight) < 4;
|
||||
for (const line of lines) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = line;
|
||||
log.appendChild(div);
|
||||
}
|
||||
if (atBottom) log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
|
||||
function setState(state) {
|
||||
if (!state) return;
|
||||
const s = document.getElementById('state');
|
||||
s.innerHTML = ''+`
|
||||
<div>Day: <span class="mono">${state.day}</span></div>
|
||||
<div>Hours Left Today: <span class="mono">${state.hours_left}</span></div>
|
||||
<div>Meals Today: <span class="mono">${state.meals}</span></div>
|
||||
<div>Earned Today: <span class="mono">${state.earned}</span></div>
|
||||
<div>Total Earned: <span class="mono">${state.earned_total}</span></div>
|
||||
<div>Debt: <span class="mono">${state.debt}</span></div>
|
||||
<div>Interest: <span class="mono">${(state.interest * 100).toFixed(0)}%</span></div>
|
||||
<div>Wage: <span class="mono">${state.wage}</span></div>
|
||||
<div>Efficiency: <span class="mono">${state.eff}</span></div>
|
||||
<div>Enhancements: <span class="mono">${state.mods}</span></div>
|
||||
`;
|
||||
const m = document.getElementById('miniState');
|
||||
if (m) {
|
||||
m.innerHTML = ''+`
|
||||
<div class="kv"><span class="label">Day</span><span class="mono">${state.day}</span></div>
|
||||
<div class="kv"><span class="label">Hours</span><span class="mono">${state.hours_left}</span></div>
|
||||
<div class="kv"><span class="label">Debt</span><span class="mono">${state.debt}</span></div>
|
||||
<div class="kv"><span class="label">Interest</span><span class="mono">${(state.interest*100).toFixed(0)}%</span></div>
|
||||
<div class="kv"><span class="label">Wage</span><span class="mono">${state.wage}</span></div>
|
||||
<div class="kv"><span class="label">Eff</span><span class="mono">${state.eff}</span></div>
|
||||
<div class="kv"><span class="label">Mods</span><span class="mono">${state.mods}</span></div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function setGameOver(summary) {
|
||||
if (!summary) return;
|
||||
appendLog(['', 'GAME OVER', summary]);
|
||||
for (const btn of document.querySelectorAll('button[data-action]')) btn.disabled = true;
|
||||
}
|
||||
|
||||
async function doAction(action, value) {
|
||||
try {
|
||||
const data = await api(action, value);
|
||||
if (data.messages) appendLog(data.messages);
|
||||
if (data.state) setState(data.state);
|
||||
if (data.game_over) setGameOver(data.final_summary || '');
|
||||
return data;
|
||||
} catch (e) {
|
||||
appendLog(['Error: ' + e.message]);
|
||||
}
|
||||
}
|
||||
|
||||
async function onLoad() {
|
||||
await doAction('start');
|
||||
}
|
||||
|
||||
async function handleWork() {
|
||||
const s = prompt('How many hours would you like to work?');
|
||||
if (s == null) return;
|
||||
const hours = parseInt(s, 10);
|
||||
if (!Number.isFinite(hours)) return appendLog(['Invalid entry.']);
|
||||
await doAction('work', hours);
|
||||
}
|
||||
|
||||
async function handleSleep() {
|
||||
const s = prompt('How many hours would you like to sleep?');
|
||||
if (s == null) return;
|
||||
const hours = parseInt(s, 10);
|
||||
if (!Number.isFinite(hours)) return appendLog(['Invalid entry.']);
|
||||
await doAction('sleep', hours);
|
||||
}
|
||||
|
||||
async function handleEnhance() {
|
||||
const resp = await doAction('enhance');
|
||||
if (resp && resp.can_install) {
|
||||
const ok = confirm('Install an enhancement?');
|
||||
if (ok) await doAction('install_enhancement');
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', onLoad);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Corpus Worker RPG</h1>
|
||||
<h1>Days In Fortuna</h1>
|
||||
<div class="row">
|
||||
<button onclick="resetGame()">Reset Game</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>Status</h2>
|
||||
<div id="miniState" class="content"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2>Actions</h2>
|
||||
<div class="content">
|
||||
@@ -145,29 +32,38 @@
|
||||
<button data-action onclick="doAction('eat')">Eat</button>
|
||||
<button data-action onclick="handleEnhance()">Search Enhancements</button>
|
||||
<button data-action onclick="doAction('quit')">Quit</button>
|
||||
<button data-action onclick="doAction('reset')">Reset</button>
|
||||
</div>
|
||||
<div class="sep"></div>
|
||||
<div class="muted">Tip: Sleep 8h and eat twice daily to maintain efficiency.</div>
|
||||
<div class="muted">
|
||||
<p>Tip: Sleep 8h and eat twice daily to maintain efficiency.</p>
|
||||
|
||||
<p>This program is a simulation of the life of a Corpus worker on Venus. You are trying to work off your debt, which has been passed down through your family for generations. As the last of your family, the burden is entirely on your shoulders.</p>
|
||||
|
||||
<p>Click the button above associated with what you want to do in order to progress.</p>
|
||||
|
||||
<p>Enhancements can be rented from the Corpus, which will increase your possible wages.</p>
|
||||
|
||||
<p>It is recommended that you sleep at least 8 hours a day and eat twice a day, which takes 1 hour per meal, to keep your efficiency up.</p>
|
||||
|
||||
<p>Interest is applied daily. Should your debt grow too high, a team of Corpus members will arrest you and replace parts of you with robotic ones to increase the profit you create. This will lower your debt however, as body parts are worth a lot of credits.</p>
|
||||
|
||||
Good luck!
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<section class="panel log">
|
||||
<h2>Log</h2>
|
||||
<div id="log" class="content"></div>
|
||||
</section>
|
||||
|
||||
async function resetGame() {
|
||||
// Clear log and re-enable action buttons
|
||||
const log = document.getElementById('log');
|
||||
log.innerHTML = '';
|
||||
for (const btn of document.querySelectorAll('button[data-action]')) btn.disabled = false;
|
||||
await doAction('reset');
|
||||
await doAction('start');
|
||||
}
|
||||
<section class="panel" style="grid-column: 1 / span 2;">
|
||||
<section class="panel hidden">
|
||||
<h2>State</h2>
|
||||
<div id="state" class="content"></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user