feat: obchod, černé můry, netopýr, pavouk a denní úkoly u chytání motýlků
CI / Generate TypeScript types (push) Successful in 15s
CI / Server unit tests (push) Successful in 23s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 1m2s
CI / Playwright E2E tests (push) Successful in 1m33s
CI / Build and push Docker image (push) Successful in 49s
CI / Notify (push) Successful in 1s

- obchod s pomůckami a trvalými vylepšeními (větší síťka, strašák, zpevněná síťka) – mince mají trvalý smysl
- černé můry se míchají mezi motýly; chycení (i magnetem) ubere hodně úlovků
- ptáci silnější, plašič dražší a kratší, zloději chodí častěji podle bohatství
- denní úkol s odměnou + achievementy/odznaky
- netopýr v noci loví motýly, pavouk zamotá síťku pavučinou – oba na zaklikání
- nákupní hlášky rozlišují nedostatek mincí od jiné chyby; herní smyčka se pozastaví při skryté záložce

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stánek Pavel
2026-07-27 10:23:09 +02:00
co-authored by Claude Opus 4.8
parent e3f439bde0
commit 252d105408
22 changed files with 1384 additions and 43 deletions
+71 -1
View File
@@ -12,10 +12,18 @@ import {
defeatThief,
caterpillarAte,
defeatCaterpillar,
mothHit,
buyPremium,
waspSpray,
buyInsurance,
buyUpgrade,
getAchievements,
getLeaderboard,
InsufficientCoinsError,
UpgradeError,
UpgradeId,
} from "../butterflies";
import { CatchButterfliesData } from "../../../types";
import { CatchButterfliesData, BuyUpgradeData } from "../../../types";
const router = express.Router();
@@ -112,6 +120,68 @@ router.post("/defeatCaterpillar", async (req: Request, res, next) => {
} catch (e: any) { next(e) }
});
router.post("/moth", async (req: Request, res, next) => {
try {
const login = getLogin(parseToken(req));
const data = await mothHit(login);
res.status(200).json(data);
} catch (e: any) { next(e) }
});
router.post("/buyPremium", async (req: Request, res, next) => {
try {
const login = getLogin(parseToken(req));
const data = await buyPremium(login);
res.status(200).json(data);
} catch (e: any) {
if (e instanceof InsufficientCoinsError) return res.status(402).json({ error: e.message });
next(e);
}
});
router.post("/waspSpray", async (req: Request, res, next) => {
try {
const login = getLogin(parseToken(req));
const data = await waspSpray(login);
res.status(200).json(data);
} catch (e: any) {
if (e instanceof InsufficientCoinsError) return res.status(402).json({ error: e.message });
next(e);
}
});
router.post("/insurance", async (req: Request, res, next) => {
try {
const login = getLogin(parseToken(req));
const data = await buyInsurance(login);
res.status(200).json(data);
} catch (e: any) {
if (e instanceof InsufficientCoinsError) return res.status(402).json({ error: e.message });
next(e);
}
});
router.post("/buyUpgrade", async (req: Request<{}, any, BuyUpgradeData["body"]>, res, next) => {
try {
const login = getLogin(parseToken(req));
if (!req.body?.item) return res.status(400).json({ error: "Chybné parametry volání" });
const data = await buyUpgrade(login, req.body.item as UpgradeId);
res.status(200).json(data);
} catch (e: any) {
if (e instanceof InsufficientCoinsError) return res.status(402).json({ error: e.message });
if (e instanceof UpgradeError) return res.status(400).json({ error: e.message });
next(e);
}
});
router.get("/achievements", async (req: Request, res, next) => {
try {
const login = getLogin(parseToken(req));
const data = await getAchievements(login);
res.status(200).json(data);
} catch (e: any) { next(e) }
});
router.get("/leaderboard", async (req: Request, res, next) => {
try {
getLogin(parseToken(req));