feat: CLI generator --seed, --pony-count, --scene-count, --json, --quiet flags

This commit is contained in:
2026-08-09 08:11:14 +00:00
parent 422b504921
commit f80c8aff79
3 changed files with 229 additions and 72 deletions

View File

@@ -418,35 +418,90 @@ def print_test_table(all_tests):
# === HUVUDKØRSEL ===
def main():
random.seed() # Tilfældig seed hver gang
import sys
print_header("MY LITTLE PONY: TAILS OF EQUESTRIA")
print(" — Ny Spiller Generator —")
print(" Genereret af Hermes AI GM")
# Parse CLI args
parser_type = "argparse" # avoid import if not needed
args = {
"seed": None,
"pony_count": None,
"scene_count": None,
"json": False,
"quiet": False,
}
raw = sys.argv[1:]
i = 0
while i < len(raw):
a = raw[i]
if a == "--seed" and i + 1 < len(raw):
args["seed"] = int(raw[i + 1])
i += 2
elif a == "--pony-count" and i + 1 < len(raw):
args["pony_count"] = int(raw[i + 1])
i += 2
elif a == "--scene-count" and i + 1 < len(raw):
args["scene_count"] = int(raw[i + 1])
i += 2
elif a == "--json":
args["json"] = True
i += 1
elif a == "--quiet":
args["quiet"] = True
i += 1
else:
i += 1
# Generer 4-6 ponyer
ant_al_ponyer = random.randint(4, 6)
print(f"\nGenererer {ant_al_ponyer} ponyer...")
# Seed RNG
if args["seed"] is not None:
random.seed(args["seed"])
else:
random.seed()
result = {
"ponies": [],
"theme": None,
"location": None,
"scenes": [],
"tests": [],
"outcome": None,
}
if not args["quiet"]:
print_header("MY LITTLE PONY: TAILS OF EQUESTRIA")
print(" — Ny Spiller Generator —")
print(" Genereret af Hermes AI GM")
# Generate ponies
ant_al_ponyer = args["pony_count"] or random.randint(4, 6)
if not args["quiet"]:
print(f"\nGenererer {ant_al_ponyer} ponyer...")
ponies = [generer_pony() for _ in range(ant_al_ponyer)]
result["ponies"] = ponies
print_header("DINE PONYER")
for p in ponies:
print_pony(p)
if not args["quiet"]:
print_header("DINE PONYER")
for p in ponies:
print_pony(p)
# Vælg tema og setting
# Select theme and setting
tema = random.choice(THEMAER)
sted = random.choice(EQUESTRIA_STEDER)
print_header(f"EVENTYR: {tema['titel'].upper()}")
print(f" SETTING: {sted['navn']}{sted['beskrivelse']}")
print(f" Fjende: {tema['fjende']}")
print(f" Stakes: {tema['stakes']}")
result["theme"] = tema["titel"]
result["location"] = sted["navn"]
# Kør scener (5-7)
scenes = tema['scener']
ant_al_scener = min(len(scenes), random.randint(5, 7))
if not args["quiet"]:
print_header(f"EVENTYR: {tema['titel'].upper()}")
print(f" SETTING: {sted['navn']}{sted['beskrivelse']}")
print(f" Fjende: {tema['fjende']}")
print(f" Stakes: {tema['stakes']}")
# Run scenes
scenes = tema["scener"]
ant_al_scener = args["scene_count"] or min(len(scenes), random.randint(5, 7))
scenes_at_koere = scenes[:ant_al_scener]
print_header(f"HANDLING ({ant_al_scener} SCENER)")
if not args["quiet"]:
print_header(f"HANDLING ({ant_al_scener} SCENER)")
all_tests = []
scene_nummer = 0
@@ -454,22 +509,24 @@ def main():
scene_nummer += 1
scene_navn, scene_beskrivelse, egenskab, svaerhedsgrad = scene
print(f"\n{'' * 60}")
print(f" SCENE {scene_nummer}: {scene_navn.upper()}")
print(f"{'' * 60}")
print(f" {scene_beskrivelse}")
if not args["quiet"]:
print(f"\n{'' * 60}")
print(f" SCENE {scene_nummer}: {scene_navn.upper()}")
print(f"{'' * 60}")
print(f" {scene_beskrivelse}")
# Tilfældig NPC-møde (20% chance)
# Random NPC encounter (20% chance)
if random.random() < 0.2:
npc = random.choice(KENDTE_NPCS)
handling = random.choice(npc["handlinger"])
print(f"\n 🎭 NPC-MØDE: {npc['navn']} ({npc['race']}) dukker op og {handling}")
print(f" ({npc['personlighed']})")
if not args["quiet"]:
print(f"\n 🎭 NPC-MØDE: {npc['navn']} ({npc['race']}) dukker op og {handling}")
print(f" ({npc['personlighed']})")
# Vælg hvilken pony der tester (tilfældig, men foretrækker relevante stats)
# Pick test pony
test_pony = random.choice(ponies)
# Find relevant talent baseret på egenskab
# Find relevant talent
relevant_talent = None
if egenskab == "krop":
for t in test_pony["talenter"]:
@@ -487,47 +544,89 @@ def main():
relevant_talent = t
break
result = test(test_pony, egenskab, svaerhedsgrad, relevant_talent)
all_tests.append(result)
print_test(result, len(all_tests))
r = test(test_pony, egenskab, svaerhedsgrad, relevant_talent)
all_tests.append(r)
result["scenes"].append({
"number": scene_nummer,
"name": scene_navn,
"test": r,
})
if not args["quiet"]:
print_test(r, len(all_tests))
# Hvis succes, lav en bonus-test fra en anden pony (for variation)
if result["udfald"] == "SUCCES" and result["overskud"] >= 2:
# Bonus test on big success
if r["udfald"] == "SUCCES" and r["overskud"] >= 2:
bonus_pony = random.choice([p for p in ponies if p["navn"] != test_pony["navn"]])
bonus_egen = random.choice(EGENSKABER)
bonus_sv = random.choice(["let", "normal", "svaert"])
bonus_result = test(bonus_pony, bonus_egen, bonus_sv)
all_tests.append(bonus_result)
print_test(bonus_result, len(all_tests))
print(f"\n 🌟 BONUS: {bonus_pony['navn']} hjælper med!")
if not args["quiet"]:
print_test(bonus_result, len(all_tests))
print(f"\n 🌟 BONUS: {bonus_pony['navn']} hjælper med!")
# Slutopgørelse
print_header("SLUTOPOPGØRELSE")
# Final tally
succeser = sum(1 for t in all_tests if t["udfald"] == "SUCCES")
fiaskoer = sum(1 for t in all_tests if t["udfald"] == "MISLYKKES")
fantastiske_total = sum(t["fantastiske"] for t in all_tests)
print(f"\n Total succeser: {succeser}")
print(f" Total fiaskoer: {fiaskoer}")
print(f" Fantastiske terninger (6): {fantastiske_total}")
if succeser > fiaskoer:
print(f"\n 🌟 SEJR! Ponyerne har overvundet {tema['fjende']}!")
print(f" {tema['stakes']}")
outcome = "SEJR"
if fantastiske_total >= 3:
print(f"EPISKE SEJR! Alle i Equestria hylder dem!")
outcome = "EPISKE_SEJR"
elif succeser == fiaskoer:
print(f"\n ⚖️ BLANDET RESULTAT. Ponyerne har kæmpet hårdt, men {tema['fjende']} trækker sig tilbage midlertidigt.")
print(f" {tema['stakes']}")
outcome = "BLANDET"
else:
print(f"\n 💀 Nederlag. {tema['fjende']} har vundet denne gang.")
print(f" {tema['stakes']}")
outcome = "NEDERLAG"
result["outcome"] = outcome
print_test_table(all_tests)
if not args["quiet"]:
print_header("SLUTOPOPGØRELSE")
print(f"\n Total succeser: {succeser}")
print(f" Total fiaskoer: {fiaskoer}")
print(f" Fantastiske terninger (6): {fantastiske_total}")
print(f"\n{'=' * 60}")
print(" FÆRDIG")
print(f"{'=' * 60}")
if succeser > fiaskoer:
print(f"\n 🌟 SEJR! Ponyerne har overvundet {tema['fjende']}!")
print(f" {tema['stakes']}")
if fantastiske_total >= 3:
print(f" ✦ EPISKE SEJR! Alle i Equestria hylder dem!")
elif succeser == fiaskoer:
print(f"\n ⚖️ BLANDET RESULTAT. Ponyerne har kæmpet hårdt, men {tema['fjende']} trækker sig tilbage midlertidigt.")
print(f" {tema['stakes']}")
else:
print(f"\n 💀 Nederlag. {tema['fjende']} har vundet denne gang.")
print(f" {tema['stakes']}")
print_test_table(all_tests)
print(f"\n{'=' * 60}")
print(" FÆRDIG")
print(f"{'=' * 60}")
if args["json"]:
import json
# Strip non-serializable data
out = {
"seed": args["seed"],
"ponies": ponies,
"theme": tema["titel"],
"location": sted["navn"],
"outcome": outcome,
"successes": succeser,
"failures": fiaskoer,
"fantastic_rolls": fantastiske_total,
"tests": [
{
"pony": t["pony"],
"stat": t["egenskab"],
"dice": t["resultat"],
"successes": t["succeser"],
"outcome": t["udfald"],
}
for t in all_tests
],
}
print(json.dumps(out, ensure_ascii=False, indent=2))
if __name__ == "__main__":

View File

@@ -8,6 +8,7 @@ import PonySelectPage from './pages/PonySelectPage';
import GameScenePage from './pages/GameScenePage';
import GameEndPage from './pages/GameEndPage';
import * as api from './services/api';
import * as achievements from './services/achievements';
import './App.css';
// Fallback pony data if API fails to load
@@ -18,32 +19,17 @@ const DEFAULT_PONIES = [
{ name: 'Alicorn', emoji: '👑', img: 'alicorn.png', bonus: 'Magi + vinger 🌟', color: '#FFD700', diceBonus: 2 },
];
// Achievement hook
// Achievement hook — thin wrapper around the service
function useAchievements() {
const [stats, setStats] = useState(() => {
try {
return JSON.parse(localStorage.getItem('pony_stats') || '{"wins":0,"losses":0,"games":0,"bestScore":0}');
} catch { return { wins: 0, losses: 0, games: 0, bestScore: 0 }; }
});
const [stats, setStats] = useState(() => achievements.getStats());
const recordGame = useCallback((victory, score) => {
setStats(prev => {
const next = {
...prev,
games: prev.games + 1,
wins: victory ? prev.wins + 1 : prev.wins,
losses: victory ? prev.losses : prev.losses + 1,
bestScore: Math.max(prev.bestScore, score || 0),
};
localStorage.setItem('pony_stats', JSON.stringify(next));
return next;
});
setStats(achievements.recordGame(victory, score));
}, []);
const resetStats = useCallback(() => {
const zero = { wins: 0, losses: 0, games: 0, bestScore: 0 };
setStats(zero);
localStorage.setItem('pony_stats', JSON.stringify(zero));
achievements.resetStats();
setStats(achievements.getStats());
}, []);
return { stats, recordGame, resetStats };

View File

@@ -0,0 +1,72 @@
/**
* Achievement system — deterministic, persistent, localStorage-backed.
*
* Tracks wins, losses, total games, and best score.
* Syncs with backend when game ends.
*/
const STORAGE_KEY = 'pony_stats';
const DEFAULT_STATS = { wins: 0, losses: 0, games: 0, bestScore: 0 };
function loadStats() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) return JSON.parse(raw);
} catch { /* ignore */ }
return { ...DEFAULT_STATS };
}
function saveStats(stats) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(stats));
}
/**
* Record a completed game.
* @param {boolean} victory — whether the player won
* @param {number} score — number of successes
* @returns {Object} updated stats
*/
export function recordGame(victory, score) {
const stats = loadStats();
stats.games += 1;
if (victory) {
stats.wins += 1;
} else {
stats.losses += 1;
}
stats.bestScore = Math.max(stats.bestScore, score || 0);
saveStats(stats);
return stats;
}
/**
* Reset all achievement stats.
*/
export function resetStats() {
saveStats({ ...DEFAULT_STATS });
}
/**
* Get current stats.
* @returns {Object}
*/
export function getStats() {
return loadStats();
}
/**
* Compute derived achievement badges.
* @param {Object} stats
* @returns {string[]} badge labels
*/
export function computeBadges(stats) {
const badges = [];
if (stats.games >= 1) badges.push('🎮 Første spil');
if (stats.wins >= 1) badges.push('🌟 Første sejr');
if (stats.games >= 5) badges.push('🎯 5 spil');
if (stats.wins >= 5) badges.push('⭐ 5 sejre');
if (stats.bestScore >= 5) badges.push('🏆 Perfekt run');
if (stats.games >= 10) badges.push('👑 Pony Mester!');
return badges;
}