diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..e56ceee39bf4c972ddd29993ba3d6994476fda09 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +__pycache__/ +*.pyc +.env +.venv/ +venv/ +.git/ +.gitignore +*.log diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..73bae98eba945556475096768c3f13804bee080d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,111 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +image/background/background.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/arena.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/command_centre.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/communication_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/convention_centre.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/forrest.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/gas_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/greenhouse.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/hangar.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/hospital.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/launchpad.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/living_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/repair_shop.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/robot_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/solar_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D_interia/weapon_shop.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/arena.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/arena.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/command_centre.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/command_centre.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/communication_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/communication_station.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/convention_centre.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/convention_centre.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/forrest.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/forrest.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/gas_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/gas_station.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/greenhouse.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/greenhouse.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/hangar.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/hangar.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/hospital.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/hospital.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/launchpad.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/launchpad.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/living_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/living_area.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/repair_shop.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/repair_shop.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/robot_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/robot_station.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/solar_station.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/solar_station.png filter=lfs diff=lfs merge=lfs -text +image/building_2D/weapon_shop.jpeg filter=lfs diff=lfs merge=lfs -text +image/building_2D/weapon_shop.png filter=lfs diff=lfs merge=lfs -text +image/building/car_park.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/command_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/docker.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/fuel_storage_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/gathering_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/green_house_experimental.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/laboratory.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/launching_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/living_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/meeting_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/mine.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/mining_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/planting_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/recreation_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/satellite.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/sleep_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/stand_alone_mining_unit.jpeg filter=lfs diff=lfs merge=lfs -text +image/building/stargate.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/cleaner_full.png filter=lfs diff=lfs merge=lfs -text +image/character/cleaner.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/cleaner.png filter=lfs diff=lfs merge=lfs -text +image/character/communicator_full.png filter=lfs diff=lfs merge=lfs -text +image/character/communicator.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/communicator.png filter=lfs diff=lfs merge=lfs -text +image/character/courier_full.png filter=lfs diff=lfs merge=lfs -text +image/character/courier.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/courier.png filter=lfs diff=lfs merge=lfs -text +image/character/farmer_full.png filter=lfs diff=lfs merge=lfs -text +image/character/farmer.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/farmer.png filter=lfs diff=lfs merge=lfs -text +image/character/humanoid_robot_full.png filter=lfs diff=lfs merge=lfs -text +image/character/humanoid_robot.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/humanoid_robot.png filter=lfs diff=lfs merge=lfs -text +image/character/Main_female_character_full.png filter=lfs diff=lfs merge=lfs -text +image/character/Main_female_character.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/Main_female_character.png filter=lfs diff=lfs merge=lfs -text +image/character/Main_male_character_full.png filter=lfs diff=lfs merge=lfs -text +image/character/Main_male_character.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/Main_male_character.png filter=lfs diff=lfs merge=lfs -text +image/character/mechanic_full.png filter=lfs diff=lfs merge=lfs -text +image/character/mechanic.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/mechanic.png filter=lfs diff=lfs merge=lfs -text +image/character/medic_full.png filter=lfs diff=lfs merge=lfs -text +image/character/medic.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/medic.png filter=lfs diff=lfs merge=lfs -text +image/character/navigator_full.png filter=lfs diff=lfs merge=lfs -text +image/character/navigator.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/navigator.png filter=lfs diff=lfs merge=lfs -text +image/character/pilot_full.png filter=lfs diff=lfs merge=lfs -text +image/character/pilot.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/pilot.png filter=lfs diff=lfs merge=lfs -text +image/character/wheel_robot_full.png filter=lfs diff=lfs merge=lfs -text +image/character/wheel_robot.jpeg filter=lfs diff=lfs merge=lfs -text +image/character/wheel_robot.png filter=lfs diff=lfs merge=lfs -text +image/interia/isolated_automation_area.jpeg filter=lfs diff=lfs merge=lfs -text +image/interia/laboratory_place.jpeg filter=lfs diff=lfs merge=lfs -text +image/interia/sleeping_place.jpeg filter=lfs diff=lfs merge=lfs -text +image/mission/huge_automated_cargo_truck.jpeg filter=lfs diff=lfs merge=lfs -text +image/mission/huge_mobile_truck.jpeg filter=lfs diff=lfs merge=lfs -text +image/mission/huge_robot.jpeg filter=lfs diff=lfs merge=lfs -text +image/mission/huge_rocket.jpeg filter=lfs diff=lfs merge=lfs -text +image/mission/space_station.jpeg filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5fdc14c1971332b45efdb053bad9693653bcb78e --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__/ +*.pyc +.env +.venv/ +venv/ +.DS_Store +*.log +deepseek_key.txt +memory/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..df2c8ff27249f0743074c3281a4541f0864fa7c0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Hugging Face Spaces (Docker SDK) - Lunar Village RPG +FROM python:3.11-slim + +ENV PYTHONUNBUFFERED=1 \ + PIP_NO_CACHE_DIR=1 \ + PORT=7860 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 7860 + +CMD ["python", "app.py"] diff --git a/README.md b/README.md index 0f7d9cb0902fc4c45e44375471b60b2a4550c73a..509b385f396e90ccd037c23b18743aac730e2c07 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,98 @@ ---- -title: MoonVillage -emoji: ๐จ -colorFrom: purple -colorTo: green -sdk: static -pinned: false ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +--- +title: Lunar Village +emoji: ๐ +colorFrom: indigo +colorTo: yellow +sdk: docker +app_port: 7860 +pinned: false +license: mit +--- + +# ๐ Lunar Village โ Moon Colony RPG + +A **SmallVill-style** online RPG set on the Moon. Walk around a lunar colony, +chat with AI-driven crew members (powered by **DeepSeek**), gather resources, +and complete the colony's mega-projects: a **huge robot**, a **mobile truck**, +an **automated cargo hauler**, a **heavy rocket**, and an **orbital space station**. + +Playable on desktop and **mobile** (touch joystick + tap-to-interact). + +**Created by Andy Kong** + +--- + +## ๐ฎ How to play + +- **Move:** on-screen joystick (mobile) or `WASD` / arrow keys (desktop). +- **Interact:** walk up to a crew member and tap the ๐ฌ button (or press `E` / `Space`) to talk. +- **Gather:** walk up to a building like the Mine or Greenhouse and tap the โ๏ธ button to collect resources. +- **Build:** open the ๐๏ธ **Missions** panel to spend resources and construct the mega-projects. + +## ๐ DeepSeek API key (important) + +The game talks to DeepSeek through a **server-side proxy** (`/api/chat`) so your +API key is never exposed to players. The key is read from an environment +variable and should be stored as a **Space Secret**, never committed to code. + +On Hugging Face: +1. Open your Space โ **Settings** โ **Variables and secrets**. +2. Add a **secret** named `DEEPSEEK_API_KEY` with your key value. +3. (Optional) add `DEEPSEEK_MODEL` (default `deepseek-chat`) and + `DEEPSEEK_BASE_URL` (default `https://api.deepseek.com`). + +> โ ๏ธ If you shared your key anywhere public (chat, screenshots, commits), +> regenerate it in the DeepSeek console before deploying. + +If no key is set, the game still runs using built-in offline personality +replies, so you can test the whole experience without any credentials. + +## ๐ Deploy to Hugging Face Spaces + +1. Create a new **Space** โ SDK: **Docker**. +2. Upload this whole folder (including `app.py`, `Dockerfile`, `requirements.txt`, + `static/`, and `image/`). +3. Add the `DEEPSEEK_API_KEY` secret (see above). +4. The Space builds the Docker image and serves the game on port `7860`. + +## ๐ฅ๏ธ Run locally + +```bash +pip install -r requirements.txt +# optional: enable AI +set DEEPSEEK_API_KEY=your_key_here # Windows (cmd) +# $env:DEEPSEEK_API_KEY="your_key_here" # Windows (PowerShell) +# export DEEPSEEK_API_KEY=your_key_here # macOS/Linux +python app.py +``` + +Then open http://localhost:7860 + +## ๐ Project structure + +``` +Kiro_RPG/ +โโ app.py # FastAPI backend + DeepSeek proxy +โโ requirements.txt +โโ Dockerfile # Hugging Face Docker Space +โโ image/ # game art (buildings, characters, missions) +โโ static/ + โโ index.html + โโ css/style.css + โโ js/ + โโ config.js # world / buildings / characters / missions data + โโ ai.js # AI chat client + โโ ui.js # HUD, dialog, missions + โโ game.js # canvas engine, player, NPCs + โโ boot.js # title screen +``` + +## ๐งฉ Tech + +- **Backend:** FastAPI + httpx (async DeepSeek proxy) +- **Frontend:** vanilla HTML5 Canvas + JS (no build step, loads fast on mobile) +- **AI:** DeepSeek Chat (OpenAI-compatible API) + +--- + +Created by **Andy Kong**. diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..731e106e37af181e4d6d1b4f06bce99f73f8cd19 --- /dev/null +++ b/app.py @@ -0,0 +1,338 @@ +""" +Lunar Village - a SmallVill-style online RPG set on the Moon. +FastAPI backend: serves the static game and proxies AI chat to DeepSeek. + +The DeepSeek API key is read from the DEEPSEEK_API_KEY environment variable +(set it as a Secret in your Hugging Face Space). It is NEVER sent to the client. + +Created by Andy Kong. +""" +import os +import re +import json +import logging +from datetime import datetime, timezone +from typing import List, Optional + +import httpx +from fastapi import FastAPI, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from fastapi.staticfiles import StaticFiles +from fastapi.responses import FileResponse, JSONResponse +from pydantic import BaseModel, Field + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger("lunar-village") + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +STATIC_DIR = os.path.join(BASE_DIR, "static") +IMAGE_DIR = os.path.join(BASE_DIR, "image") +MEMORY_DIR = os.path.join(BASE_DIR, "memory") +os.makedirs(MEMORY_DIR, exist_ok=True) + +DATA_DIR = os.path.join(BASE_DIR, "data") +os.makedirs(DATA_DIR, exist_ok=True) +INVENTORY_PATH = os.path.join(DATA_DIR, "inventory.json") + + +def load_inventory() -> dict: + if os.path.isfile(INVENTORY_PATH): + try: + with open(INVENTORY_PATH, "r", encoding="utf-8") as f: + return json.load(f) + except Exception: # noqa: BLE001 + pass + return {"resources": {}, "updated": None} + + +def save_inventory(resources: dict) -> dict: + data = { + "resources": {k: float(v) for k, v in resources.items()}, + "updated": datetime.now(timezone.utc).isoformat(timespec="seconds"), + } + with open(INVENTORY_PATH, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + return data + +MAX_MEMORY_ENTRIES = 60 # keep the most recent N per character +MEMORY_IN_PROMPT = 10 # how many recent memories to feed the AI + + +def _safe_id(cid: str) -> str: + return re.sub(r"[^a-zA-Z0-9_-]", "", cid or "")[:64] + + +def _mem_path(cid: str) -> str: + return os.path.join(MEMORY_DIR, f"{_safe_id(cid)}.json") + + +def load_memory(cid: str) -> dict: + path = _mem_path(cid) + if os.path.isfile(path): + try: + with open(path, "r", encoding="utf-8") as f: + return json.load(f) + except Exception: # noqa: BLE001 + pass + return {"id": _safe_id(cid), "name": "", "entries": []} + + +def save_memory(cid: str, data: dict) -> None: + try: + with open(_mem_path(cid), "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + except Exception as exc: # noqa: BLE001 + logger.warning("Could not save memory for %s: %s", cid, exc) + + +def append_memory(cid: str, text: str, name: str = "") -> dict: + data = load_memory(cid) + if name and not data.get("name"): + data["name"] = name + data.setdefault("entries", []).append({ + "t": datetime.now(timezone.utc).isoformat(timespec="seconds"), + "text": text.strip(), + }) + data["entries"] = data["entries"][-MAX_MEMORY_ENTRIES:] + save_memory(cid, data) + return data + + +def memory_prompt(cid: str) -> str: + data = load_memory(cid) + entries = data.get("entries", [])[-MEMORY_IN_PROMPT:] + if not entries: + return "" + lines = "\n".join(f"- {e['text']}" for e in entries) + return ( + "\n\nYour memories so far (oldest first, act consistently with them, " + "and follow any standing orders from the Commander):\n" + lines + ) + +DEEPSEEK_API_KEY = os.environ.get("DEEPSEEK_API_KEY", "").strip() +# Also try loading from a local key file (not uploaded to Hugging Face) +_KEY_FILE = os.path.join(BASE_DIR, "deepseek_key.txt") +if not DEEPSEEK_API_KEY and os.path.isfile(_KEY_FILE): + with open(_KEY_FILE, "r", encoding="utf-8") as _f: + DEEPSEEK_API_KEY = _f.read().strip() + +DEEPSEEK_BASE_URL = os.environ.get("DEEPSEEK_BASE_URL", "https://api.deepseek.com").rstrip("/") +DEEPSEEK_MODEL = os.environ.get("DEEPSEEK_MODEL", "deepseek-chat") + +# Allow a user-provided key at runtime (set via /api/set-key) +_USER_KEY = {"key": ""} + +app = FastAPI(title="Lunar Village", version="1.0.0") + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["*"], + allow_headers=["*"], +) + + +class ChatMessage(BaseModel): + role: str + content: str + + +class ChatRequest(BaseModel): + system: str = Field(default="", description="System / persona prompt for the NPC.") + messages: List[ChatMessage] = Field(default_factory=list) + temperature: float = 1.0 + max_tokens: int = 220 + character_id: Optional[str] = None # if set, that character's memory is injected + character_name: Optional[str] = None + + +class MemoryEntryRequest(BaseModel): + text: str + name: Optional[str] = None + + +class CharacterSeed(BaseModel): + id: str + name: Optional[str] = None + persona: Optional[str] = None + + +class MemoryInitRequest(BaseModel): + characters: List[CharacterSeed] = Field(default_factory=list) + + +class InventoryRequest(BaseModel): + resources: dict = Field(default_factory=dict) + + +class ChatResponse(BaseModel): + reply: str + fallback: bool = False + + +# A small offline personality-flavoured fallback so the game is still playable +# without an API key (e.g. local testing or if DeepSeek is unreachable). +FALLBACK_LINES = { + "farmer": "The greenhouse crops are holding up, but I need more water reclaimed from the ice mine.", + "mechanic": "Give me spare parts and I'll keep the rovers running. That huge truck won't build itself.", + "medic": "Radiation exposure is the real enemy up here. Stay inside during solar flares.", + "pilot": "The launch window is tight. We need fuel stabilised before the rocket can fly.", + "navigator": "I've been charting safe routes across the mare. Fewer craters, fewer breakdowns.", + "communicator": "Signal to Earth has a two-second delay. Patience, commander.", + "courier": "I move supplies between the domes. Tell me where you need them.", + "cleaner": "Moon dust gets everywhere. It clogs the airlocks if I don't keep at it.", + "humanoid_robot": "Directive acknowledged. Awaiting task assignment, commander.", + "wheel_robot": "Beep. Rolling out to the mining area for another load of ore.", + "default": "Welcome to the colony, commander. There's plenty of work to keep us all alive up here.", +} + + +def build_fallback(system: str, messages: List[ChatMessage]) -> str: + text = (system + " " + " ".join(m.content for m in messages)).lower() + for key, line in FALLBACK_LINES.items(): + if key != "default" and key in text: + return line + return FALLBACK_LINES["default"] + + +@app.get("/api/health") +async def health(): + active_key = _USER_KEY["key"] or DEEPSEEK_API_KEY + return {"ok": True, "ai_enabled": bool(active_key)} + + +class SetKeyRequest(BaseModel): + key: str = "" + + +@app.post("/api/set-key") +async def set_key(req: SetKeyRequest): + """Allow a user to provide their own DeepSeek API key for this session.""" + _USER_KEY["key"] = req.key.strip() + return {"ok": True, "ai_enabled": bool(_USER_KEY["key"] or DEEPSEEK_API_KEY)} + + +@app.post("/api/memory/init") +async def memory_init(req: MemoryInitRequest): + """Ensure a memory file exists for every character (called once on game start).""" + created = [] + for c in req.characters: + cid = _safe_id(c.id) + if not cid: + continue + if not os.path.isfile(_mem_path(cid)): + seed = {"id": cid, "name": c.name or "", "entries": []} + if c.persona: + seed["entries"].append({ + "t": datetime.now(timezone.utc).isoformat(timespec="seconds"), + "text": f"I am {c.name or cid}, {c.persona}", + }) + save_memory(cid, seed) + created.append(cid) + return {"ok": True, "created": created, "total": len(req.characters)} + + +@app.get("/api/memory") +async def memory_list(): + ids = [f[:-5] for f in os.listdir(MEMORY_DIR) if f.endswith(".json")] + return {"characters": sorted(ids)} + + +@app.get("/api/memory/{cid}") +async def memory_get(cid: str): + return load_memory(cid) + + +@app.post("/api/memory/{cid}") +async def memory_post(cid: str, req: MemoryEntryRequest): + if not req.text.strip(): + raise HTTPException(status_code=400, detail="empty memory text") + data = append_memory(cid, req.text, req.name or "") + return {"ok": True, "count": len(data.get("entries", []))} + + +@app.get("/api/inventory") +async def inventory_get(): + """Return the colony's accumulated resources (persisted to data/inventory.json).""" + return load_inventory() + + +@app.post("/api/inventory") +async def inventory_post(req: InventoryRequest): + data = save_inventory(req.resources) + return {"ok": True, **data} + + +@app.post("/api/chat", response_model=ChatResponse) +async def chat(req: ChatRequest): + # Build the system prompt, injecting this character's memory if provided. + system = req.system + if req.character_id: + system += memory_prompt(req.character_id) + + # Determine the active API key (user-provided takes priority) + active_key = _USER_KEY["key"] or DEEPSEEK_API_KEY + + # No key configured -> graceful offline fallback so the game still works. + if not active_key: + return ChatResponse(reply=build_fallback(req.system, req.messages), fallback=True) + + payload_messages = [] + if system: + payload_messages.append({"role": "system", "content": system}) + for m in req.messages: + payload_messages.append({"role": m.role, "content": m.content}) + + payload = { + "model": DEEPSEEK_MODEL, + "messages": payload_messages, + "temperature": req.temperature, + "max_tokens": req.max_tokens, + "stream": False, + } + headers = { + "Authorization": f"Bearer {active_key}", + "Content-Type": "application/json", + } + + try: + async with httpx.AsyncClient(timeout=30.0) as client: + resp = await client.post( + f"{DEEPSEEK_BASE_URL}/chat/completions", + json=payload, + headers=headers, + ) + if resp.status_code != 200: + logger.warning("DeepSeek error %s: %s", resp.status_code, resp.text[:300]) + return ChatResponse(reply=build_fallback(req.system, req.messages), fallback=True) + data = resp.json() + reply = data["choices"][0]["message"]["content"].strip() + return ChatResponse(reply=reply, fallback=False) + except Exception as exc: # noqa: BLE001 + logger.exception("DeepSeek request failed: %s", exc) + return ChatResponse(reply=build_fallback(req.system, req.messages), fallback=True) + + +# Serve game images and static assets. +if os.path.isdir(IMAGE_DIR): + app.mount("/image", StaticFiles(directory=IMAGE_DIR), name="image") + + +@app.get("/") +async def index(): + index_path = os.path.join(STATIC_DIR, "index.html") + if os.path.isfile(index_path): + # never cache the HTML so versioned asset URLs are always picked up + return FileResponse(index_path, headers={"Cache-Control": "no-cache, no-store, must-revalidate"}) + return JSONResponse({"error": "index.html not found"}, status_code=404) + + +if os.path.isdir(STATIC_DIR): + app.mount("/", StaticFiles(directory=STATIC_DIR, html=True), name="static") + + +if __name__ == "__main__": + import uvicorn + + port = int(os.environ.get("PORT", "7860")) + uvicorn.run("app:app", host="0.0.0.0", port=port, reload=False) diff --git a/data/inventory.json b/data/inventory.json new file mode 100644 index 0000000000000000000000000000000000000000..41e0db4ddddd1b5e6de3a5682ed81b03fcdd8ee7 --- /dev/null +++ b/data/inventory.json @@ -0,0 +1,11 @@ +{ + "resources": { + "ore": 153.90000000000174, + "metal": 14.600000000000168, + "fuel": 177.35000000000232, + "food": 0.2, + "energy": 272.90000000000657, + "parts": 175.2999999999926 + }, + "updated": "2026-07-12T14:21:08+00:00" +} \ No newline at end of file diff --git a/image/background/background.jpeg b/image/background/background.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..16ec52b57dbbe6683d81b3e47e4f4c0ac41ce9c2 --- /dev/null +++ b/image/background/background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8718ae2c02852aede8ddf6e18fd979ada4e9a01ef0e847b735d59f2393692a2e +size 138658 diff --git a/image/building/car_park.jpeg b/image/building/car_park.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d21044a5c2e5efb667f348349f42d89371a2d39a --- /dev/null +++ b/image/building/car_park.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ac69f15d8f31713bf2f9bddf2a0bfc18c103afb3981804db0804ba3b56844a4 +size 398325 diff --git a/image/building/command_area.jpeg b/image/building/command_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..1ba42cf3d518daa51052017c7895836636f1354a --- /dev/null +++ b/image/building/command_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:74af7fe21034cf1e2bbda972a3e146d05acf506f76cde852e224f91b0cce526e +size 262167 diff --git a/image/building/docker.jpeg b/image/building/docker.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e82193625a7c8e46a8156ba3631ae190d79176c8 --- /dev/null +++ b/image/building/docker.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed3b65ee7fd6542df2b5847bd74a462793822542e31a5e8f94ff168122b562dd +size 248997 diff --git a/image/building/fuel_storage_area.jpeg b/image/building/fuel_storage_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9f2070ea20edbc6b59a044396623e35aad8c1ef8 --- /dev/null +++ b/image/building/fuel_storage_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39ca1f5623c298441f34e0af5ef8e2507a64b96ac4dee03f995cc4cd1c5447c0 +size 250712 diff --git a/image/building/gathering_area.jpeg b/image/building/gathering_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7bc7d33c68a776089bbc5be5b92fbd81681d3c63 --- /dev/null +++ b/image/building/gathering_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf28b0f36caac1db5accd09c8f0aebd9479dddc6c670e0b7cc22e008d41e3d8f +size 347204 diff --git a/image/building/green_house_experimental.jpeg b/image/building/green_house_experimental.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..383795ece2509c50e74dcf2b44e7a0cba9843e5c --- /dev/null +++ b/image/building/green_house_experimental.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b28ea321a89c7874ebf6692de1a7c9edbaaea985bfe6eca6e6caa3a453c64c1f +size 419022 diff --git a/image/building/laboratory.jpeg b/image/building/laboratory.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..aecd6f9a7d777cd7445c95d1a35b62b4bd2fb3dd --- /dev/null +++ b/image/building/laboratory.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84c655ce945672861c34058e24e1d70370a73bd7b302f44cfb50be33d2ff5fa5 +size 232520 diff --git a/image/building/launching_area.jpeg b/image/building/launching_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c2455ccadeaff934b04cf03facc997f69396421f --- /dev/null +++ b/image/building/launching_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ccac701ca02310fea0b3e0cbe2aa67fe5fc87f0a36204054d09085f2741b614f +size 276610 diff --git a/image/building/living_area.jpeg b/image/building/living_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8c0c2499a5b16bd391cf2abfc59c80ba35dbc2c7 --- /dev/null +++ b/image/building/living_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eba23050bb67b5cab6982180fc087737a4d7bc342474c71bf8a3b1ae6304bd44 +size 400319 diff --git a/image/building/meeting_area.jpeg b/image/building/meeting_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9bc31bdfd4189a1b06c5be6a9aeb3542736e93b8 --- /dev/null +++ b/image/building/meeting_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11fe175fda9bf35d35e755a7aba31251f011d5d3226c05879930b3eb8778150e +size 280751 diff --git a/image/building/mine.jpeg b/image/building/mine.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..45cdbc7a3eb111370da2c15fbc48151e13b72f0e --- /dev/null +++ b/image/building/mine.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3a8b7d3b8e6d8e77d10093217d9843067a472ed34aa9d141e953b1e5c8f5b1f +size 269865 diff --git a/image/building/mining_area.jpeg b/image/building/mining_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..155b586ca8bd9aec046d34a415c321204cb1f4f2 --- /dev/null +++ b/image/building/mining_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcbf14333e8acf92b4a60f9d46517d19038512a3c4842ff77a734380489b5843 +size 406062 diff --git a/image/building/planting_area.jpeg b/image/building/planting_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7a21faea678d067602f89f7a841ecd94a00ed6a4 --- /dev/null +++ b/image/building/planting_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a05b4ec72fd6d676413bf4d3bb72d76692361edca77af10086c235336c6d9b59 +size 330495 diff --git a/image/building/recreation_area.jpeg b/image/building/recreation_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5aec1a7fe8f55108985f59881001fd50b478273c --- /dev/null +++ b/image/building/recreation_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e56003bfe11200dfb05a88164b907c046bdd01c214934d9077502ef378a5043a +size 381017 diff --git a/image/building/satellite.jpeg b/image/building/satellite.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a002f2113cb9a2f7858a305bd6e7b5acbff5a78a --- /dev/null +++ b/image/building/satellite.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:066198660d8f534792e7e5ca09d65b179f39465fe7fc5c80648d362baca2b0f2 +size 211025 diff --git a/image/building/sleep_area.jpeg b/image/building/sleep_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7f412a2d233cca2e7c03a1b35cf2a9224fc5cc8a --- /dev/null +++ b/image/building/sleep_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f23f82832f76bf9f78f422bb4fa61063ede8da1022cd96a696738d3b3623381d +size 386639 diff --git a/image/building/stand_alone_mining_unit.jpeg b/image/building/stand_alone_mining_unit.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c76aee84aa62f64d6d3c54649f6b14ba70b2668b --- /dev/null +++ b/image/building/stand_alone_mining_unit.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9a3d51b8ee491281e8dda91ea0e1511ddba06a98ad8eecef522804ff6adef01 +size 259051 diff --git a/image/building/stargate.jpeg b/image/building/stargate.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..47de190dc2b7ac822f1bf8c1efe0392531f1bf6f --- /dev/null +++ b/image/building/stargate.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:116ff80630536e3b6ec6bc6d29d110898c2e37bac9668424ff643f3611adceb2 +size 195638 diff --git a/image/building_2D/arena.jpeg b/image/building_2D/arena.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8dfc288cffe65663099dcc278a1d461d48d3571b --- /dev/null +++ b/image/building_2D/arena.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4630c9c3b4e229f6a6db104ad3f0352eac4a7348634f2e61353647627878f020 +size 317827 diff --git a/image/building_2D/arena.png b/image/building_2D/arena.png new file mode 100644 index 0000000000000000000000000000000000000000..f1f51e88486191f9550ff42519a53317ce6201c2 --- /dev/null +++ b/image/building_2D/arena.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f78241fd01629b58ac10bae678865adae32b0302817e956123d84e6ae5e8b286 +size 1136978 diff --git a/image/building_2D/command_centre.jpeg b/image/building_2D/command_centre.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..13ae6b7c1536ea5a6b0eb63577943546fca66e4b --- /dev/null +++ b/image/building_2D/command_centre.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:277ea39518e7286eafeac7ac9cbeac699b387c1da266925503c17d18b9d149cc +size 301797 diff --git a/image/building_2D/command_centre.png b/image/building_2D/command_centre.png new file mode 100644 index 0000000000000000000000000000000000000000..b4c23cc754fd81ba7bdaaffa0dd06349bb5bb4c4 --- /dev/null +++ b/image/building_2D/command_centre.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af14e4f271d652128b74b6743affe637ba7487f04d0f82a828162658b3f98f02 +size 977672 diff --git a/image/building_2D/communication_station.jpeg b/image/building_2D/communication_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..523104e0dde78844bc4276ce056b0e94bac3427a --- /dev/null +++ b/image/building_2D/communication_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70ea3f2c983bcd259f4f7e35e150458464906b61e1ec6cc19e760c026d183946 +size 238732 diff --git a/image/building_2D/communication_station.png b/image/building_2D/communication_station.png new file mode 100644 index 0000000000000000000000000000000000000000..54a3c413891ffe2d0bd1f1d24bc170f6ac494db4 --- /dev/null +++ b/image/building_2D/communication_station.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5eb7c34570326e1ef580db757216fa7627b23ca57b61e3674899e98a749da256 +size 619307 diff --git a/image/building_2D/convention_centre.jpeg b/image/building_2D/convention_centre.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..742a0244aeabf6a1149f6c6bd8aad873c0075d0c --- /dev/null +++ b/image/building_2D/convention_centre.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f2c293529735afa647cf08c6d75b21fbc62894f1e22ec1e8cd86534fac611d8 +size 316790 diff --git a/image/building_2D/convention_centre.png b/image/building_2D/convention_centre.png new file mode 100644 index 0000000000000000000000000000000000000000..ff887d40b7b293f0a49439910bb498b945c0a856 --- /dev/null +++ b/image/building_2D/convention_centre.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a455e578e0bcf577b02c9121d67455daab95eac0bc006f37d28d3c2779c04f6 +size 1288970 diff --git a/image/building_2D/forrest.jpeg b/image/building_2D/forrest.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..96518d45d76c2558e6b8fe486d35a86a4730a909 --- /dev/null +++ b/image/building_2D/forrest.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:906ead1cb4b4f4561ccbfa4eaff60c2f848850fe031cd878754e12faf00b36fc +size 297147 diff --git a/image/building_2D/forrest.png b/image/building_2D/forrest.png new file mode 100644 index 0000000000000000000000000000000000000000..4dd1c50e4012171cfb9e7396496fc0c9396ce851 --- /dev/null +++ b/image/building_2D/forrest.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b741340d46032835c8b09be4bda203cc74eb8c245a9c45ff5dab13eb2c7a2cd +size 1049523 diff --git a/image/building_2D/gas_station.jpeg b/image/building_2D/gas_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f9a71322eca2ad93f4c48c5584495a1d382afa74 --- /dev/null +++ b/image/building_2D/gas_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eec02b247aec7f48278f9f18828030ebc4181f216943ce1b7b7ab68105d34533 +size 243701 diff --git a/image/building_2D/gas_station.png b/image/building_2D/gas_station.png new file mode 100644 index 0000000000000000000000000000000000000000..f4d9c1ad9ee36bffeb326b357838b229e42559b6 --- /dev/null +++ b/image/building_2D/gas_station.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:840150eb1c75672c38720e3d3bb65c8b2261e54e61a0828bbcbf9aefdbc8aba4 +size 1185812 diff --git a/image/building_2D/greenhouse.jpeg b/image/building_2D/greenhouse.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..718a785307a21bbdc1ae34341fe32d8dee4ec4ed --- /dev/null +++ b/image/building_2D/greenhouse.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa0ac9836b8f85c9a7cf2eb75d9be66274c0aba484f5420df0db12173a9d9100 +size 315769 diff --git a/image/building_2D/greenhouse.png b/image/building_2D/greenhouse.png new file mode 100644 index 0000000000000000000000000000000000000000..178439a3c397576137ea91aae7c641854830a160 --- /dev/null +++ b/image/building_2D/greenhouse.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4b82ff68262ed7803afbe7b76eedf5a003a7240cddd900747bedb0db0d2505f +size 1378803 diff --git a/image/building_2D/hangar.jpeg b/image/building_2D/hangar.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d9034bf827749508669a843022992fe28aa0eeee --- /dev/null +++ b/image/building_2D/hangar.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f3c917f59731e4cb4ec778196c60e982f504bdd6bd7de8650ae22836bd94876 +size 301075 diff --git a/image/building_2D/hangar.png b/image/building_2D/hangar.png new file mode 100644 index 0000000000000000000000000000000000000000..ae699bfebeef8a4ee1a6191557764f37efb95715 --- /dev/null +++ b/image/building_2D/hangar.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1bf7555f3fffb3d4c254b0ba767474e4e9fbc02c1e2e93d6fcf587fe25dc246a +size 1052022 diff --git a/image/building_2D/hospital.jpeg b/image/building_2D/hospital.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..bacd541949e05ad052ea2e70e59c58c8dc34aff7 --- /dev/null +++ b/image/building_2D/hospital.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df951ab4270b4f7bf37b5c7034a8c8d49226d35b94da6440953377f0f5404638 +size 303640 diff --git a/image/building_2D/hospital.png b/image/building_2D/hospital.png new file mode 100644 index 0000000000000000000000000000000000000000..910e22219b726db40cf499654881b3919feec882 --- /dev/null +++ b/image/building_2D/hospital.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66a83f09c5a3e292678606c74a26254571770bde96c574aafb545f5ff287aeeb +size 1159783 diff --git a/image/building_2D/launchpad.jpeg b/image/building_2D/launchpad.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..784f2a17cad2e2631f95d78128955cfd5279ef25 --- /dev/null +++ b/image/building_2D/launchpad.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a73a95493a08694da8bff3b06dfe5f7356d69458e0f58facd0cc57ca968a8d89 +size 285241 diff --git a/image/building_2D/launchpad.png b/image/building_2D/launchpad.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e6de2ed289de69d60fa04cb10d7334c29d1630 --- /dev/null +++ b/image/building_2D/launchpad.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfdc7ca4ab8a1c93dae733930f8a205d2517d2fb0120ac2ba91dfe6df1724a1a +size 973898 diff --git a/image/building_2D/living_area.jpeg b/image/building_2D/living_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..03603b0a3dda95880cf3f8f19136885aa282a482 --- /dev/null +++ b/image/building_2D/living_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aafd0f25b7d94c377c9b5f0751a6e6f66809dd2701be3816c9586ce101164462 +size 310677 diff --git a/image/building_2D/living_area.png b/image/building_2D/living_area.png new file mode 100644 index 0000000000000000000000000000000000000000..2c05ec81995b4fdbbfb0347882c33b1668b12866 --- /dev/null +++ b/image/building_2D/living_area.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dff09679d77f306a87cabf17e343fde81c50956f68047ea5f015abeeaba5efbe +size 1165188 diff --git a/image/building_2D/repair_shop.jpeg b/image/building_2D/repair_shop.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..26e603604ff4d9a71f1ed598790bf6e9b7cf87eb --- /dev/null +++ b/image/building_2D/repair_shop.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6460cc5791b908bd991279a0284bc91d31d9221c65bb4a76b55bff521c877b2f +size 301016 diff --git a/image/building_2D/repair_shop.png b/image/building_2D/repair_shop.png new file mode 100644 index 0000000000000000000000000000000000000000..fee47caa0390026ac01bdde6a0d4cee91d26066b --- /dev/null +++ b/image/building_2D/repair_shop.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7fade5850a323e6f0affaa5300747e792db0a38e663237e3d5509da7a50975d1 +size 993766 diff --git a/image/building_2D/robot_station.jpeg b/image/building_2D/robot_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..af0e30fc6fe60862b02d23297f9631df02fbfb23 --- /dev/null +++ b/image/building_2D/robot_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5aab9840419cdd7db3b6f7c39e5377b0b63e4731c879155c798b363d3e0c3bf1 +size 354936 diff --git a/image/building_2D/robot_station.png b/image/building_2D/robot_station.png new file mode 100644 index 0000000000000000000000000000000000000000..926b09a7a893a60457fd2141c1816d1b082a9495 --- /dev/null +++ b/image/building_2D/robot_station.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc65a58459f1da0fd6ca84f6d5f0f060a17b9b9b5ba914816624afb4e5716de4 +size 1382095 diff --git a/image/building_2D/solar_station.jpeg b/image/building_2D/solar_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..84607b78652b8efaa9946074e86b8b81585cc723 --- /dev/null +++ b/image/building_2D/solar_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e09382787c58b0a254d493551a644f8ef92bf890e6c780dd7bc5d40f6afcbdb +size 259282 diff --git a/image/building_2D/solar_station.png b/image/building_2D/solar_station.png new file mode 100644 index 0000000000000000000000000000000000000000..972e1fa2a828dca56615996cdf90c7f189816b1b --- /dev/null +++ b/image/building_2D/solar_station.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f51c89846885e659668e4763bda3042d8cd33a0e9f02a5e4dfb412ac56f96bd +size 821503 diff --git a/image/building_2D/weapon_shop.jpeg b/image/building_2D/weapon_shop.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..95c6c7e48c526f2e7733eefeb3d5e6e8d1bf7777 --- /dev/null +++ b/image/building_2D/weapon_shop.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d34837ab61fee459c34ad4934ec76eeabd86bd0e7821df3d16d8448d0129f4a7 +size 274515 diff --git a/image/building_2D/weapon_shop.png b/image/building_2D/weapon_shop.png new file mode 100644 index 0000000000000000000000000000000000000000..7255c6a9ccb785a18ed7c949203e6425f3e64724 --- /dev/null +++ b/image/building_2D/weapon_shop.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:faa38f40a24e9fe749dfb629a50b1825eaacdba61bb85dedfa7488241c602717 +size 822058 diff --git a/image/building_2D_interia/arena.jpeg b/image/building_2D_interia/arena.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..630308f8bf525d795919a90b4f02de54f06fb1f1 --- /dev/null +++ b/image/building_2D_interia/arena.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fc32b4e6bb4f5be8a7a10fefb8ac787cacfcc85d59d6d4a063b551259c064fe +size 351567 diff --git a/image/building_2D_interia/command_centre.jpeg b/image/building_2D_interia/command_centre.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6f5f60a5dd7e976864450b26356fcf5c186355e9 --- /dev/null +++ b/image/building_2D_interia/command_centre.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15808a8932bc7c2fcfb03935747318779c32a79a318f6d5b1750e80f0bd11638 +size 422448 diff --git a/image/building_2D_interia/communication_station.jpeg b/image/building_2D_interia/communication_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..58c50de5700321e38c21c8002a08af99dfe99737 --- /dev/null +++ b/image/building_2D_interia/communication_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b40395dfc2dec3c3fdd724ab5ef3fd112cc53947e929014944f38b7d383c5579 +size 427707 diff --git a/image/building_2D_interia/convention_centre.jpeg b/image/building_2D_interia/convention_centre.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e8862310d5bf55936fc4bfa9b99bc6c528546149 --- /dev/null +++ b/image/building_2D_interia/convention_centre.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:913440ae1ebd2c6ab45324c57f42073520d49339b1c4f993f269b28f4f55f524 +size 390061 diff --git a/image/building_2D_interia/forrest.jpeg b/image/building_2D_interia/forrest.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..640ccf2d248943b1e858791a49a12d124469cc12 --- /dev/null +++ b/image/building_2D_interia/forrest.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:220ec2ed147331ee12d7e7fe401bb42eece8af894a0f22faf86639e7aede349a +size 492314 diff --git a/image/building_2D_interia/gas_station.jpeg b/image/building_2D_interia/gas_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..629bef244d08e4cddc85c6729147ccc32dbc4b4f --- /dev/null +++ b/image/building_2D_interia/gas_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5254f741055c3ab10c4e39f681c250c96334bbb95af07085c7e2bf802bf723b5 +size 394446 diff --git a/image/building_2D_interia/greenhouse.jpeg b/image/building_2D_interia/greenhouse.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9356b5273a7a4a4694a5446bcd7c8bb53f434dec --- /dev/null +++ b/image/building_2D_interia/greenhouse.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edb28785370f04fab84dcc3be9612b74c492448a9effcffd686bebe242ad1dc2 +size 563206 diff --git a/image/building_2D_interia/hangar.jpeg b/image/building_2D_interia/hangar.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c951083af16417b03cb40ea00478966b0ae640ba --- /dev/null +++ b/image/building_2D_interia/hangar.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f487dbdf9d9ae5febcce18a83aa74a2d143622aad6b88d21139e4224a931f68 +size 434221 diff --git a/image/building_2D_interia/hospital.jpeg b/image/building_2D_interia/hospital.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4b176fa065375c86614fffb411f8f2b4933024a7 --- /dev/null +++ b/image/building_2D_interia/hospital.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1d0a6aaf4042089b3fe26f57c27af0d9ec5467798e705fb807e0a93bd6d2c46 +size 337525 diff --git a/image/building_2D_interia/launchpad.jpeg b/image/building_2D_interia/launchpad.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3663077672688f90aa2bd0f2bc2fa86a4f1f8072 --- /dev/null +++ b/image/building_2D_interia/launchpad.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2290a324a0504a03894225c7641c2bdcf0893f7c33576cf161e5d9b7e103980 +size 483745 diff --git a/image/building_2D_interia/living_area.jpeg b/image/building_2D_interia/living_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7ea85563d7aedd8e08916b7a6ff2641ba9c1d8df --- /dev/null +++ b/image/building_2D_interia/living_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9748f19a7084a7db6fd8ad11a12b538aa2ff21c2d4a78c7c623d2bbdef17a32f +size 396715 diff --git a/image/building_2D_interia/repair_shop.jpeg b/image/building_2D_interia/repair_shop.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..01f4dc03a7b239dbf0356e7875257c37bc352069 --- /dev/null +++ b/image/building_2D_interia/repair_shop.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc3c75c9fefa6a511b345601ba77bb6196dc56aef4296ab63c603eaaf1ba4b92 +size 413352 diff --git a/image/building_2D_interia/robot_station.jpeg b/image/building_2D_interia/robot_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0f4680c69495402d67c585a9d0580c8a4e860012 --- /dev/null +++ b/image/building_2D_interia/robot_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb3ecd0702823429b66afd58529c158d702b4e49c3e02994d4fc9f01c3b01b9b +size 488707 diff --git a/image/building_2D_interia/solar_station.jpeg b/image/building_2D_interia/solar_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c55eaa35863abb1b09d9dbceaffab8f85a1ef685 --- /dev/null +++ b/image/building_2D_interia/solar_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3472117be30a54a9ff1a3cb4a86b3be3892ce3b226dc3f2af673ac2fef8f248b +size 391448 diff --git a/image/building_2D_interia/weapon_shop.jpeg b/image/building_2D_interia/weapon_shop.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a3c9122b5b0faea7ff9352049d04519288a98561 --- /dev/null +++ b/image/building_2D_interia/weapon_shop.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bd9f70c7b080c49d4548b3942dd9ba7605aa5d4a8a247860aff28ece8cd92f4 +size 453652 diff --git a/image/character/Main_female_character.jpeg b/image/character/Main_female_character.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5fd3408ee40d2378ce205f78ea57ba9a1107c910 --- /dev/null +++ b/image/character/Main_female_character.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6bdb5cac48cc97b629b2431bd0ef6a50483890b6a9c27605307d77a7b9d57b7 +size 245938 diff --git a/image/character/Main_female_character.png b/image/character/Main_female_character.png new file mode 100644 index 0000000000000000000000000000000000000000..98d28ec984a329da48910cbb3a0fc9bacafb87c9 --- /dev/null +++ b/image/character/Main_female_character.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b979d98f30b2069f5aedac172560c44f59cdefbe57b3fc822254c90e5be1eddc +size 1205710 diff --git a/image/character/Main_female_character_face.png b/image/character/Main_female_character_face.png new file mode 100644 index 0000000000000000000000000000000000000000..039a0b4cc6bde4b3a3649cc97ee3b72da18d8450 Binary files /dev/null and b/image/character/Main_female_character_face.png differ diff --git a/image/character/Main_female_character_full.png b/image/character/Main_female_character_full.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb9213f423425fc8698157ed86f13927730b57d --- /dev/null +++ b/image/character/Main_female_character_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d40962018f6e2d21a15b56a78b409e24374f3dd1aed7a30f25e87ca315e45c43 +size 490746 diff --git a/image/character/Main_male_character.jpeg b/image/character/Main_male_character.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..fe1c1bf793f3054d06c458a701b03c807a1e38fe --- /dev/null +++ b/image/character/Main_male_character.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e4ca4911b0500083a212e4949f36d1ff1b66f8e6289dd6c060ddd617c166c00 +size 267947 diff --git a/image/character/Main_male_character.png b/image/character/Main_male_character.png new file mode 100644 index 0000000000000000000000000000000000000000..05927d849b0aa603277cafb99f6ea18fea1be56b --- /dev/null +++ b/image/character/Main_male_character.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d506edaad333768e694a56a903dd557087bb8e8db0389bcf036fa68b5c536eca +size 1375138 diff --git a/image/character/Main_male_character_face.png b/image/character/Main_male_character_face.png new file mode 100644 index 0000000000000000000000000000000000000000..6332ae6243ff14533a5e9d2316942856e1ce30b4 Binary files /dev/null and b/image/character/Main_male_character_face.png differ diff --git a/image/character/Main_male_character_full.png b/image/character/Main_male_character_full.png new file mode 100644 index 0000000000000000000000000000000000000000..a491a049740c31dccad9a7f42ff6517b5cdc161f --- /dev/null +++ b/image/character/Main_male_character_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a69f099c373bfb50486266cdd77c1e8c69a133fbd1635a2430757dd37a6fcc0 +size 543961 diff --git a/image/character/cleaner.jpeg b/image/character/cleaner.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d9b31e19ec8239466f361bd9b4ad989f11e25e6b --- /dev/null +++ b/image/character/cleaner.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3385fdf05d006da1947f344c53f341501cdd75a42f6a82ae13c950cce86eab2b +size 270483 diff --git a/image/character/cleaner.png b/image/character/cleaner.png new file mode 100644 index 0000000000000000000000000000000000000000..7d5a457575876908cde35c4a463c82b5ddba1431 --- /dev/null +++ b/image/character/cleaner.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1aa7e6550bd13a9ac4d95322dacdf0864a5a8ef4124f3da96eb33b033bafbb6b +size 1366723 diff --git a/image/character/cleaner_face.png b/image/character/cleaner_face.png new file mode 100644 index 0000000000000000000000000000000000000000..a63603c1ae01b9cd512034dd10cad0e2d43e7417 Binary files /dev/null and b/image/character/cleaner_face.png differ diff --git a/image/character/cleaner_full.png b/image/character/cleaner_full.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd69a32c3f57b8c20f469935fbe43ab639a64b5 --- /dev/null +++ b/image/character/cleaner_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4487621f8b192a137a3e1f2c69fa7b0a204a08c705c31d4247857c98a6b3cca2 +size 547985 diff --git a/image/character/communicator.jpeg b/image/character/communicator.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6b6121404957cf3860fe0afbd0bc924f7aaee75a --- /dev/null +++ b/image/character/communicator.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd6e6d2a6505f0b4e40d07e56db0809ed970b0a2c1e8034bd11508b39905c65d +size 248520 diff --git a/image/character/communicator.png b/image/character/communicator.png new file mode 100644 index 0000000000000000000000000000000000000000..3a8b9eed40e1b801813f6acb3bb82b9a043760ea --- /dev/null +++ b/image/character/communicator.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fdda5c4bdedf0bc1c2d16ebec628f675cab8d9bea0af703ae69945af866d3fe0 +size 1283320 diff --git a/image/character/communicator_face.png b/image/character/communicator_face.png new file mode 100644 index 0000000000000000000000000000000000000000..8015fe7276308b1a7f9515961f91aac79fb49e8a Binary files /dev/null and b/image/character/communicator_face.png differ diff --git a/image/character/communicator_full.png b/image/character/communicator_full.png new file mode 100644 index 0000000000000000000000000000000000000000..5d400ae2f769f4415f3a98b7c7297f60657f4a93 --- /dev/null +++ b/image/character/communicator_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2264e05e3c03d780a951f4821e580f8d18b08370a3651b0633991a3faffb9f71 +size 458046 diff --git a/image/character/courier.jpeg b/image/character/courier.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c55bcb07e6dd9d390bf49a7ee7c957ac4a85197c --- /dev/null +++ b/image/character/courier.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb1af775363e87e5a7e85777a2dbff551e987bf349dbf2c44c027892508ef87a +size 249603 diff --git a/image/character/courier.png b/image/character/courier.png new file mode 100644 index 0000000000000000000000000000000000000000..2c16de028137f6812a3e91b3f3b68d8e212b6f3e --- /dev/null +++ b/image/character/courier.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5cf8154acf7909b1c3b4e996ae5526e214f68cc5dbc0955dba202df040dfc140 +size 1230838 diff --git a/image/character/courier_face.png b/image/character/courier_face.png new file mode 100644 index 0000000000000000000000000000000000000000..0e9a4992f62feb74d2cecc54f26698cd6dfbb4f7 Binary files /dev/null and b/image/character/courier_face.png differ diff --git a/image/character/courier_full.png b/image/character/courier_full.png new file mode 100644 index 0000000000000000000000000000000000000000..1742f6d9908cde819d2877325ac0bba4a63b4742 --- /dev/null +++ b/image/character/courier_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4598f9f3ab2253d0852cf93e9795c3f73e37920adf759d1d49b0da8985b26ec5 +size 444722 diff --git a/image/character/farmer.jpeg b/image/character/farmer.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6b9c89694d33a9399e3ea7d77376736d0aeb6a0f --- /dev/null +++ b/image/character/farmer.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90bd3ab0a6ada06d656a06dcb633204b4426e8675fdf419f302d3b2163daa660 +size 252649 diff --git a/image/character/farmer.png b/image/character/farmer.png new file mode 100644 index 0000000000000000000000000000000000000000..7c010c29aeaefb10843a2a2c1f06934eab13af63 --- /dev/null +++ b/image/character/farmer.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4f372e2cef87a261cc14d39a22c6e87fbc166d5f148c22fd2f40734ca0f3bca +size 1341824 diff --git a/image/character/farmer_face.png b/image/character/farmer_face.png new file mode 100644 index 0000000000000000000000000000000000000000..58d5e1dd3e026be50b9fa7291bc07a46164cffa5 Binary files /dev/null and b/image/character/farmer_face.png differ diff --git a/image/character/farmer_full.png b/image/character/farmer_full.png new file mode 100644 index 0000000000000000000000000000000000000000..1e0887cd26077e2991d649c3373bc97d83528e7b --- /dev/null +++ b/image/character/farmer_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8111c10ee26982d45457c4067afa08d6681a607f2aa69537a23021fa58331fae +size 470692 diff --git a/image/character/humanoid_robot.jpeg b/image/character/humanoid_robot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8dddbbffecfa281bc3c8b208ccd534d384fe5288 --- /dev/null +++ b/image/character/humanoid_robot.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff5a3023b256af8c5114f4a5bdccc7071b702fff851d2d7609f95beaf1e73d0f +size 229943 diff --git a/image/character/humanoid_robot.png b/image/character/humanoid_robot.png new file mode 100644 index 0000000000000000000000000000000000000000..b511642ac9ba9a66234480997e68e78dc42e9321 --- /dev/null +++ b/image/character/humanoid_robot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f9f1b7e22a2444c1719a65405c6e9dc6bb76f3344954bb022da1caeacff0365 +size 1038164 diff --git a/image/character/humanoid_robot_face.png b/image/character/humanoid_robot_face.png new file mode 100644 index 0000000000000000000000000000000000000000..6f7b42df4a58db3e0a5d711e895cb52766dcac83 Binary files /dev/null and b/image/character/humanoid_robot_face.png differ diff --git a/image/character/humanoid_robot_full.png b/image/character/humanoid_robot_full.png new file mode 100644 index 0000000000000000000000000000000000000000..b849becec6822cf22daa57320efcd1f0278f168f --- /dev/null +++ b/image/character/humanoid_robot_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28b2463870bc2862f930a887f0b08d75d8c5f33d83e6425ed23b9c4c34b44c11 +size 383744 diff --git a/image/character/mechanic.jpeg b/image/character/mechanic.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4c7ca3c959ba306d73ea2783e11605e609b021a4 --- /dev/null +++ b/image/character/mechanic.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e78e00d42431733671365eab04595ce41787150db08e158109415648bf88ebb +size 277858 diff --git a/image/character/mechanic.png b/image/character/mechanic.png new file mode 100644 index 0000000000000000000000000000000000000000..9d53bd0da3f22c2c82c555e031c09ffa21f508f7 --- /dev/null +++ b/image/character/mechanic.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55a3e30237987eca9ef5fe4b0d3e624ab737ab815e2f3f203b26e8201d4a74f2 +size 1400964 diff --git a/image/character/mechanic_face.png b/image/character/mechanic_face.png new file mode 100644 index 0000000000000000000000000000000000000000..0c6eefa65e3442e09456b3e6f6d249e2f81c489d Binary files /dev/null and b/image/character/mechanic_face.png differ diff --git a/image/character/mechanic_full.png b/image/character/mechanic_full.png new file mode 100644 index 0000000000000000000000000000000000000000..d2c3e70dc69f1d5957c36c3ee7334cc8337cd6d4 --- /dev/null +++ b/image/character/mechanic_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c70c7b31001ca13024fd94e7cacbc756064016697ea68ee3e28605e0587ab7dd +size 478162 diff --git a/image/character/medic.jpeg b/image/character/medic.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..cdf3f40eba717a42d866cfe654e17426e2fc80f5 --- /dev/null +++ b/image/character/medic.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a021ed997ef03801cc761bcdbcc9e1b5e1ee0e097bc5a219baf952e070051eb7 +size 265823 diff --git a/image/character/medic.png b/image/character/medic.png new file mode 100644 index 0000000000000000000000000000000000000000..f37634ad10c7a2988611166311fa52bf0beebd43 --- /dev/null +++ b/image/character/medic.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5797b6996dcaebc89c5b4294f067e96afdd39d8bdbd6e641dc472cd955745cad +size 1338425 diff --git a/image/character/medic_face.png b/image/character/medic_face.png new file mode 100644 index 0000000000000000000000000000000000000000..7a3f9d1edd75771b5dcbbb2bf87d245dd2334577 Binary files /dev/null and b/image/character/medic_face.png differ diff --git a/image/character/medic_full.png b/image/character/medic_full.png new file mode 100644 index 0000000000000000000000000000000000000000..43e61939d9fd1431682270f1101722bb755bc89b --- /dev/null +++ b/image/character/medic_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd2a349739ea1e5d1b94a5f959c000b6f47312f6ad28c833ed9ab4594918cfad +size 528154 diff --git a/image/character/navigator.jpeg b/image/character/navigator.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..1b7d6fd7ef7ede809f352f2c252941b9289881ce --- /dev/null +++ b/image/character/navigator.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85f24f080f3aa92c2132440af3e94bb78e3c8ecc0863b31bced9ffd86624a58f +size 242223 diff --git a/image/character/navigator.png b/image/character/navigator.png new file mode 100644 index 0000000000000000000000000000000000000000..5f1c81623b77313ed61a5bef123763b11a393707 --- /dev/null +++ b/image/character/navigator.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbf3b5fd8f95c8e564d9d24448a9d0ed0b095b9721ceae9266f6bbcf121e5482 +size 1158505 diff --git a/image/character/navigator_face.png b/image/character/navigator_face.png new file mode 100644 index 0000000000000000000000000000000000000000..e2d46b63c216194b44e54dbf32a0f42ef3518de9 Binary files /dev/null and b/image/character/navigator_face.png differ diff --git a/image/character/navigator_full.png b/image/character/navigator_full.png new file mode 100644 index 0000000000000000000000000000000000000000..e4f638a91dd5be049d831bb0cc6cd2e9105e672a --- /dev/null +++ b/image/character/navigator_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a493cbbf15694086738cb8e283b98bdaad281ab1dcefcacbb53c1fb757975591 +size 399419 diff --git a/image/character/pilot.jpeg b/image/character/pilot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..910538d47ffeceee642438333ac5938eabcf1af4 --- /dev/null +++ b/image/character/pilot.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b52897bba828c535ce1c3bc19a3715b6620834ac66eeaa2eb277ad834758c551 +size 252430 diff --git a/image/character/pilot.png b/image/character/pilot.png new file mode 100644 index 0000000000000000000000000000000000000000..529cf779a159a02e74aba99a0db63ae731a925ea --- /dev/null +++ b/image/character/pilot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:831ead9112fb4b66a193863126efefce87869039abfd52cc639f5f261dbc4107 +size 1305207 diff --git a/image/character/pilot_face.png b/image/character/pilot_face.png new file mode 100644 index 0000000000000000000000000000000000000000..eb52fc4904bf47bd8ace0bdf13bd3d3c2e5fbe09 Binary files /dev/null and b/image/character/pilot_face.png differ diff --git a/image/character/pilot_full.png b/image/character/pilot_full.png new file mode 100644 index 0000000000000000000000000000000000000000..f1e36d411ad6f92875edacf68e0a55f21718433b --- /dev/null +++ b/image/character/pilot_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18ba973ca20636e29a8558426ea345c97aa7fb5ef3e2653d3178445c6389e2aa +size 544020 diff --git a/image/character/wheel_robot.jpeg b/image/character/wheel_robot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f30a1ae93495c292a908acaaa133bb21a4712062 --- /dev/null +++ b/image/character/wheel_robot.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc65d55329f3285ef103343b60f20be768637119a534bde93be215451662bbad +size 233638 diff --git a/image/character/wheel_robot.png b/image/character/wheel_robot.png new file mode 100644 index 0000000000000000000000000000000000000000..948d9b43b177369028a8d5085bdd991a5153b587 --- /dev/null +++ b/image/character/wheel_robot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe41845c62a6de8c47c8b60511bb24a3564b82107e25133c614dc64a21bc2280 +size 1057422 diff --git a/image/character/wheel_robot_face.png b/image/character/wheel_robot_face.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd64ccb63f18c88c430c786735eb3fc883b0798 Binary files /dev/null and b/image/character/wheel_robot_face.png differ diff --git a/image/character/wheel_robot_full.png b/image/character/wheel_robot_full.png new file mode 100644 index 0000000000000000000000000000000000000000..8961d346e27bf7193e6b6dd295e20e3852e94461 --- /dev/null +++ b/image/character/wheel_robot_full.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d140e58266f06fb8a178f30417193e66fb0bb880558a654572cd57fcb46e508e +size 477002 diff --git a/image/interia/isolated_automation_area.jpeg b/image/interia/isolated_automation_area.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..eff321e16d72c28358860e84798233d0148411b4 --- /dev/null +++ b/image/interia/isolated_automation_area.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f263a32d6390a0ab5035f3f89c6f83d63217cc2b3e9387a49fedf4f3b25aa3f1 +size 440248 diff --git a/image/interia/laboratory_place.jpeg b/image/interia/laboratory_place.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f9d941948016c417112a7a18d09a490a42f6c330 --- /dev/null +++ b/image/interia/laboratory_place.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be1a5c06b192786a2b7160e61def1b2cc57f7d012b9b1f563504f1a4323384d2 +size 335697 diff --git a/image/interia/sleeping_place.jpeg b/image/interia/sleeping_place.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7dc3f47379b58409546acc69b8e8d71b1166d843 --- /dev/null +++ b/image/interia/sleeping_place.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:535fbdf3c5e58e68c267a96a8f4aeaba2ef1308efa2f6387dd186634842631ad +size 345728 diff --git a/image/mission/huge_automated_cargo_truck.jpeg b/image/mission/huge_automated_cargo_truck.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..002e7a6315812ec3b4181ec45afb7d3e369a4982 --- /dev/null +++ b/image/mission/huge_automated_cargo_truck.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a4ce88266331c0512b0a1bc9f6796ea9f99bff0e6899a3fae5bf62110b4e363 +size 375365 diff --git a/image/mission/huge_mobile_truck.jpeg b/image/mission/huge_mobile_truck.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a56124997a0dfd21b51e00f5d3ace5fabe6dfff8 --- /dev/null +++ b/image/mission/huge_mobile_truck.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:706afd05ee151d43c17c683f168bf67869d26976b71aaa04112aa56f10229033 +size 338763 diff --git a/image/mission/huge_robot.jpeg b/image/mission/huge_robot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..bc682d58aa7374bf7b233155a583f4ba05455b7b --- /dev/null +++ b/image/mission/huge_robot.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a7ea3d52ecb2d81730246522983f75e4a5afc2e368ae07b0f3a89b9fb355b72 +size 296320 diff --git a/image/mission/huge_rocket.jpeg b/image/mission/huge_rocket.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3f4b0754450bdf8d194a3fa601e08da6fbffecb0 --- /dev/null +++ b/image/mission/huge_rocket.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13d08b3929b16d6a0ad7f7e8207f9760411b3c7e8ae186e5989722fd5bab0e4d +size 273281 diff --git a/image/mission/space_station.jpeg b/image/mission/space_station.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8998715cecd871d5caf0467f84d34a16f6112fb9 --- /dev/null +++ b/image/mission/space_station.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:042e045d56851dded7516f0a3821c18cd53c0f8fb0ca77653d737b2cb8756ab5 +size 252304 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ed08a2d7fd2909569e3be96458c9ee05fac45ec --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +fastapi==0.115.0 +uvicorn[standard]==0.30.6 +httpx==0.27.2 +pydantic==2.9.2 diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000000000000000000000000000000000000..9e403c0f05cc359ad27f4f2356b46ee587ef6952 --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,395 @@ +/* Lunar Village - styles (mobile-first, responsive) + Created by Andy Kong */ + +* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; } +html, body { + height: 100%; overflow: hidden; + background: #05060f; + color: #e8e8f0; + font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + touch-action: none; + user-select: none; +} +#game { position: fixed; inset: 0; display: block; } + +/* ---------- HUD ---------- */ +#hud { position: fixed; inset: 0; pointer-events: none; z-index: 10; } +#topbar { + position: absolute; top: 0; left: 0; right: 0; + display: flex; justify-content: space-between; align-items: center; + gap: 8px; padding: env(safe-area-inset-top, 8px) 10px 8px; + padding-top: max(env(safe-area-inset-top), 8px); +} +#resources { + display: flex; flex-wrap: wrap; gap: 6px; + background: rgba(10, 12, 24, 0.65); + backdrop-filter: blur(6px); + border: 1px solid rgba(255,255,255,0.08); + border-radius: 12px; padding: 6px 8px; +} +.res { display: inline-flex; align-items: center; gap: 3px; font-size: 13px; font-weight: 600; } +.res-ic { font-size: 14px; } +.pill-btn { + pointer-events: auto; + background: linear-gradient(135deg, #6c5ce7, #4834d4); + color: #fff; border: none; border-radius: 12px; + padding: 9px 12px; font-size: 13px; font-weight: 700; cursor: pointer; + box-shadow: 0 4px 14px rgba(76, 52, 212, 0.4); + white-space: nowrap; +} +.pill-btn:active { transform: scale(0.96); } +.topbar-btns { display: flex; gap: 8px; align-items: center; } +.pill-btn.ghost { + background: rgba(10, 12, 24, 0.65); border: 1px solid rgba(124,246,255,0.35); + box-shadow: none; color: #cffaff; +} +.pill-btn.profile { + background: linear-gradient(135deg, #ffd166, #f0932b); + color: #1a1200; + box-shadow: 0 4px 14px rgba(240,147,43,0.4); +} +.pill-btn.announce { + background: linear-gradient(135deg, #ff7675, #d63031); + box-shadow: 0 4px 14px rgba(214, 48, 49, 0.4); +} + +/* Broadcast banner */ +#broadcast-banner { + position: fixed; top: 0; left: 0; right: 0; z-index: 45; + display: flex; align-items: center; justify-content: center; + padding: 14px 16px; padding-top: max(env(safe-area-inset-top), 14px); + background: linear-gradient(180deg, rgba(214,48,49,0.95), rgba(214,48,49,0)); + color: #fff; font-weight: 700; font-size: 15px; text-align: center; + transform: translateY(-120%); transition: transform 0.4s ease; pointer-events: none; + text-shadow: 0 1px 3px rgba(0,0,0,0.5); +} +#broadcast-banner.show { transform: translateY(0); } + +/* Announcement composer */ +.announce-card { + width: 100%; max-width: 480px; max-height: 86vh; + background: linear-gradient(160deg, #1e1420, #0c0d1a); + border: 1px solid rgba(255, 118, 117, 0.3); + border-radius: 18px; display: flex; flex-direction: column; overflow: hidden; +} +.announce-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); } +.announce-head h2 { font-size: 18px; } +.announce-sub { font-size: 13px; color: #aab; padding: 12px 16px 0; } +.announce-input-row { display: flex; gap: 8px; padding: 12px 16px; } +#announce-input { + flex: 1; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); + border-radius: 12px; padding: 12px; color: #fff; font-size: 15px; outline: none; +} +#announce-send { + background: linear-gradient(135deg, #ff7675, #d63031); border: none; color: #fff; + font-weight: 700; padding: 0 16px; border-radius: 12px; cursor: pointer; font-size: 14px; +} +#announce-send:disabled { opacity: 0.5; cursor: not-allowed; } +#announce-send:active:not(:disabled) { transform: scale(0.95); } +.announce-quick { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 16px 8px; } +.quick-chip { + background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); + color: #cdd; border-radius: 20px; padding: 6px 10px; font-size: 12px; cursor: pointer; +} +.quick-chip:active { transform: scale(0.95); } +.announce-results { overflow-y: auto; padding: 4px 16px 16px; display: flex; flex-direction: column; gap: 8px; } +.ann-row { display: flex; gap: 10px; align-items: flex-start; } +.ann-av { + width: 34px; height: 34px; border-radius: 50%; flex: 0 0 auto; + background-color: #12142a; background-size: cover; background-position: center; + border: 2px solid #ff7675; +} +.ann-body { flex: 1; min-width: 0; } +.ann-name { font-size: 12px; font-weight: 700; color: #ffb0af; } +.ann-reply { font-size: 13px; color: #e8e8f0; line-height: 1.35; } +.ann-reply.pending { color: #889; font-style: italic; } +.ann-move-note { + background: rgba(124,246,255,0.12); border: 1px solid rgba(124,246,255,0.3); + color: #cffaff; font-size: 12px; font-weight: 600; padding: 8px 10px; border-radius: 10px; +} + +#zoom-controls { + position: absolute; right: 12px; top: 62px; + display: flex; flex-direction: column; gap: 6px; pointer-events: auto; +} +.zoom-ctl { + width: 40px; height: 40px; border-radius: 10px; font-size: 22px; font-weight: 700; + background: rgba(10, 12, 24, 0.7); color: #fff; border: 1px solid rgba(255,255,255,0.15); + cursor: pointer; line-height: 1; +} +.zoom-ctl:active { transform: scale(0.92); } + +#action-hint { + position: absolute; bottom: 108px; left: 50%; transform: translateX(-50%); + background: rgba(10, 12, 24, 0.7); padding: 5px 12px; border-radius: 20px; + font-size: 13px; font-weight: 600; color: #ffd166; + border: 1px solid rgba(255,209,102,0.3); +} +#action-hint:empty { display: none; } + +/* ---------- Mobile controls ---------- */ +#joystick { + position: fixed; bottom: 28px; left: 22px; + width: 118px; height: 118px; border-radius: 50%; + background: rgba(255,255,255,0.06); + border: 2px solid rgba(255,255,255,0.14); + z-index: 20; touch-action: none; +} +#joystick-knob { + position: absolute; top: 50%; left: 50%; + width: 52px; height: 52px; margin: -26px 0 0 -26px; border-radius: 50%; + background: radial-gradient(circle at 35% 35%, #9b8cff, #4834d4); + box-shadow: 0 4px 12px rgba(0,0,0,0.4); +} +#action-btn { + position: fixed; bottom: 40px; right: 26px; + width: 78px; height: 78px; border-radius: 50%; + font-size: 30px; border: none; cursor: pointer; + background: linear-gradient(135deg, #ffd166, #f0932b); + box-shadow: 0 6px 20px rgba(240, 147, 43, 0.5); + z-index: 20; display: none; +} +#action-btn.show { display: block; } +#action-btn:active { transform: scale(0.93); } +#enter-btn { + position: fixed; bottom: 130px; right: 26px; + padding: 10px 18px; border-radius: 14px; + font-size: 15px; font-weight: 700; border: none; cursor: pointer; + background: linear-gradient(135deg, #7cf6ff, #38bdf8); + color: #0c1020; + box-shadow: 0 6px 20px rgba(56, 189, 248, 0.4); + z-index: 20; display: none; +} +#enter-btn.show { display: block; } +#enter-btn:active { transform: scale(0.93); } + +/* ---------- Toast ---------- */ +#toast { + position: fixed; top: 64px; left: 50%; transform: translateX(-50%) translateY(-20px); + background: rgba(12, 14, 28, 0.92); color: #fff; + padding: 10px 16px; border-radius: 12px; font-size: 13px; font-weight: 600; + border: 1px solid rgba(124, 246, 255, 0.3); + opacity: 0; transition: all 0.25s ease; z-index: 40; pointer-events: none; + max-width: 90vw; text-align: center; +} +#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } + +/* ---------- Modals ---------- */ +.modal { + position: fixed; inset: 0; z-index: 50; + background: rgba(3, 4, 12, 0.72); backdrop-filter: blur(4px); + display: none; align-items: center; justify-content: center; padding: 14px; +} +.modal.show { display: flex; } +.close-x { + background: rgba(255,255,255,0.08); border: none; color: #fff; + width: 34px; height: 34px; border-radius: 50%; font-size: 16px; cursor: pointer; + flex: 0 0 auto; +} +.close-x:active { transform: scale(0.9); } + +/* ---------- Dialog ---------- */ +.dialog-card { + width: 100%; max-width: 460px; height: min(78vh, 620px); + background: linear-gradient(160deg, #16182c, #0c0d1a); + border: 1px solid rgba(124, 246, 255, 0.18); + border-radius: 18px; display: flex; flex-direction: column; overflow: hidden; + box-shadow: 0 20px 60px rgba(0,0,0,0.6); +} +.dialog-head { display: flex; align-items: center; gap: 10px; padding: 12px; border-bottom: 1px solid rgba(255,255,255,0.08); } +.dialog-avatar { + width: 46px; height: 46px; border-radius: 50%; + background-color: #12142a; + background-size: cover; background-position: center; background-repeat: no-repeat; + border: 2px solid #7cf6ff; flex: 0 0 auto; +} +.dialog-title { flex: 1; min-width: 0; } +#dialog-name { font-weight: 700; font-size: 16px; } +.role { font-size: 12px; color: #9aa; text-transform: capitalize; } +.ai-status { font-size: 11px; color: #7cf6ff; background: rgba(124,246,255,0.1); padding: 3px 7px; border-radius: 8px; } +.chat-log { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; } +.chat-line { max-width: 82%; padding: 9px 12px; border-radius: 14px; font-size: 14px; line-height: 1.4; word-wrap: break-word; } +.chat-line.npc { align-self: flex-start; background: rgba(124, 246, 255, 0.12); border: 1px solid rgba(124,246,255,0.2); border-bottom-left-radius: 4px; } +.chat-line.me { align-self: flex-end; background: linear-gradient(135deg, #6c5ce7, #4834d4); border-bottom-right-radius: 4px; } +.chat-line.typing { opacity: 0.6; font-style: italic; } +.chat-input-row { display: flex; gap: 8px; padding: 10px; border-top: 1px solid rgba(255,255,255,0.08); } +#chat-input { + flex: 1; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); + border-radius: 12px; padding: 11px 12px; color: #fff; font-size: 15px; outline: none; +} +#chat-send { + background: linear-gradient(135deg, #ffd166, #f0932b); border: none; color: #1a1200; + font-weight: 700; padding: 0 16px; border-radius: 12px; cursor: pointer; font-size: 14px; +} +#chat-send:active { transform: scale(0.95); } + +/* ---------- About panel ---------- */ +.pill-btn.about { + background: rgba(10, 12, 24, 0.65); border: 1px solid rgba(255,255,255,0.2); + box-shadow: none; color: #e8e8f0; +} +.about-card { + width: 100%; max-width: 600px; max-height: 85vh; + background: linear-gradient(160deg, #16182c, #0c0d1a); + border: 1px solid rgba(124, 246, 255, 0.22); + border-radius: 18px; display: flex; flex-direction: column; overflow: hidden; + box-shadow: 0 20px 60px rgba(0,0,0,0.6); +} +.about-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); flex: 0 0 auto; } +.about-head h2 { font-size: 18px; } +.about-body { overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-height: 0; } +.about-section { + border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; overflow: visible; + flex: 0 0 auto; +} +.about-toggle { + width: 100%; background: rgba(255,255,255,0.04); border: none; color: #e8e8f0; + padding: 12px 14px; font-size: 14px; font-weight: 700; text-align: left; cursor: pointer; + display: flex; align-items: center; gap: 8px; border-radius: 12px; +} +.about-toggle:hover { background: rgba(255,255,255,0.07); } +.about-toggle .arrow { transition: transform 0.2s; font-size: 12px; } +.about-toggle.open .arrow { transform: rotate(90deg); } +.about-content { display: none; padding: 10px 14px 14px; font-size: 13px; line-height: 1.6; color: #cdd; } +.about-content.open { display: block; } +.about-content p { margin: 0 0 8px; } +.about-content ul { margin: 4px 0 8px; padding-left: 18px; } +.about-content li { margin: 4px 0; } +.about-content .char-row { display: flex; gap: 8px; align-items: center; margin: 6px 0; } +.about-content .char-dot { width: 8px; height: 8px; border-radius: 50%; background: #7cf6ff; flex: 0 0 auto; } +.about-content strong { color: #ffd166; } +.about-content em { color: #7cf6ff; font-style: normal; } + +/* ---------- Building interior view ---------- */ +.interior-card { + width: 100%; max-width: 800px; max-height: 88vh; + background: #0c0d1a; + border: 1px solid rgba(124, 246, 255, 0.22); + border-radius: 18px; display: flex; flex-direction: column; overflow: hidden; + box-shadow: 0 20px 60px rgba(0,0,0,0.7); +} +.interior-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); } +.interior-head h2 { font-size: 16px; } +.interior-scene { position: relative; width: 100%; aspect-ratio: 16/9; overflow: hidden; } +#interior-canvas { width: 100%; height: 100%; display: block; } + +/* ---------- Character ability window ---------- */ +.char-card { + width: 100%; max-width: 440px; max-height: 88vh; + background: linear-gradient(160deg, #16182c, #0c0d1a); + border: 1px solid rgba(124, 246, 255, 0.22); + border-radius: 18px; display: flex; flex-direction: column; overflow: hidden; + box-shadow: 0 20px 60px rgba(0,0,0,0.6); +} +.char-head { display: flex; align-items: center; gap: 10px; padding: 12px; border-bottom: 1px solid rgba(255,255,255,0.08); } +.char-title { flex: 1; min-width: 0; } +#char-name { font-weight: 800; font-size: 17px; } +.char-body { overflow-y: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; } +.stat-bar-row { display: flex; align-items: center; gap: 8px; } +.stat-bar-label { width: 26px; font-size: 12px; font-weight: 700; color: #cdd; } +.stat-bar { flex: 1; height: 12px; background: rgba(255,255,255,0.08); border-radius: 7px; overflow: hidden; } +.stat-bar-fill { height: 100%; border-radius: 7px; transition: width 0.4s ease; } +.stat-bar-num { width: 62px; text-align: right; font-size: 11px; color: #aab; font-variant-numeric: tabular-nums; } +.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 4px 0; } +.stat-chip { display: flex; justify-content: space-between; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.08); border-radius: 9px; padding: 6px 9px; font-size: 12px; } +.stat-chip b { color: #ffd166; } +.stat-line { display: flex; gap: 8px; font-size: 13px; line-height: 1.35; } +.stat-line .k { flex: 0 0 92px; color: #8ab; font-weight: 600; } +.stat-line .v { flex: 1; color: #e8e8f0; } +.stat-section { margin-top: 6px; font-size: 13px; font-weight: 800; color: #7cf6ff; border-top: 1px solid rgba(255,255,255,0.08); padding-top: 8px; } +.rel-list, .fight-list { display: flex; flex-direction: column; gap: 4px; } +.rel-row, .fight-row { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; background: rgba(255,255,255,0.04); border-radius: 8px; padding: 5px 9px; } +.rel-row .ally, .fight-row .win { color: #6ee7a8; } +.rel-row .rival, .fight-row .loss { color: #ff9a9a; } +.fight-row { justify-content: flex-start; gap: 10px; } +.muted { font-size: 12px; color: #778; padding: 2px 2px; } +.tag.injured { background: rgba(248,113,113,0.2); color: #ffb4b4; padding: 1px 6px; border-radius: 6px; font-size: 11px; } +.char-actions { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 12px; border-top: 1px solid rgba(255,255,255,0.08); } +.cbtn { + flex: 1 1 auto; min-width: 88px; background: rgba(255,255,255,0.07); + border: 1px solid rgba(255,255,255,0.14); color: #e8e8f0; border-radius: 10px; + padding: 9px 10px; font-size: 13px; font-weight: 700; cursor: pointer; +} +.cbtn.talk { background: linear-gradient(135deg, #ffd166, #f0932b); color: #1a1200; border: none; } +.cbtn:active { transform: scale(0.96); } + +/* ---------- Missions ---------- */ +.missions-card { + width: 100%; max-width: 720px; max-height: 86vh; + background: linear-gradient(160deg, #16182c, #0c0d1a); + border: 1px solid rgba(255, 209, 102, 0.2); + border-radius: 18px; display: flex; flex-direction: column; overflow: hidden; +} +.missions-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); } +.missions-head h2 { font-size: 18px; } +.missions-list { overflow-y: auto; padding: 14px; display: grid; grid-template-columns: 1fr; gap: 12px; } +@media (min-width: 560px) { .missions-list { grid-template-columns: 1fr 1fr; } } +.mission-card { + display: flex; gap: 12px; background: rgba(255,255,255,0.04); + border: 1px solid rgba(255,255,255,0.08); border-radius: 14px; padding: 10px; overflow: hidden; +} +.mission-card.done { border-color: rgba(46, 213, 115, 0.4); } +.mission-img { width: 92px; height: 92px; border-radius: 10px; background-size: cover; background-position: center; flex: 0 0 auto; } +.mission-body { flex: 1; min-width: 0; } +.mission-body h3 { font-size: 15px; margin-bottom: 3px; } +.mission-body p { font-size: 12px; color: #aab; line-height: 1.35; margin-bottom: 6px; } +.mission-cost { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; } +.cost { font-size: 12px; padding: 2px 6px; border-radius: 6px; background: rgba(255,255,255,0.06); } +.cost.ok { color: #6ee7a8; } .cost.no { color: #ff7675; } +.build-btn { + background: linear-gradient(135deg, #6c5ce7, #4834d4); color: #fff; border: none; + border-radius: 10px; padding: 8px 14px; font-weight: 700; font-size: 13px; cursor: pointer; +} +.build-btn:disabled { opacity: 0.4; cursor: not-allowed; } +.build-btn:active:not(:disabled) { transform: scale(0.96); } +.mission-status { font-size: 12px; font-weight: 700; color: #ffd166; } +.mission-card.done .mission-status { color: #6ee7a8; } +.progress { height: 8px; background: rgba(255,255,255,0.1); border-radius: 6px; overflow: hidden; margin-bottom: 5px; } +.progress .bar { height: 100%; background: linear-gradient(90deg, #ffd166, #f0932b); transition: width 0.5s ease; } +.credit-small { text-align: center; font-size: 11px; color: #667; padding: 8px; } + +/* ---------- Title ---------- */ +#title { + position: fixed; inset: 0; z-index: 100; display: none; + align-items: center; justify-content: center; padding: 20px; + background: radial-gradient(circle at 50% 30%, #1a1330, #05060f 70%); + overflow-y: auto; +} +#title.show { display: flex; } +.title-inner { text-align: center; max-width: 480px; width: 100%; } +.title-badge { font-size: 64px; filter: drop-shadow(0 0 24px rgba(255,209,102,0.5)); } +#title h1 { font-size: clamp(30px, 8vw, 46px); letter-spacing: 4px; margin: 6px 0; background: linear-gradient(135deg, #ffd166, #7cf6ff); -webkit-background-clip: text; background-clip: text; color: transparent; } +.tagline { color: #aab; font-size: 14px; line-height: 1.5; margin-bottom: 20px; } +.avatar-select { display: flex; gap: 16px; justify-content: center; margin-bottom: 20px; flex-wrap: wrap; } +.avatar-opt { cursor: pointer; padding: 8px; border-radius: 14px; border: 2px solid transparent; transition: all 0.2s; } +.avatar-opt.sel { border-color: #ffd166; background: rgba(255,209,102,0.08); } +.avatar-opt:active { transform: scale(0.96); } +.avatar-pic { + width: 140px; height: 172px; border-radius: 18px; + background-color: #161831; + background-size: contain; + background-position: center center; + background-repeat: no-repeat; + border: 3px solid rgba(255,255,255,0.15); +} +.avatar-opt.sel .avatar-pic { border-color: #ffd166; } +.avatar-name { margin-top: 8px; font-weight: 700; font-size: 14px; } +.start-btn { + background: linear-gradient(135deg, #ffd166, #f0932b); color: #1a1200; border: none; + padding: 14px 34px; border-radius: 14px; font-size: 17px; font-weight: 800; cursor: pointer; + box-shadow: 0 8px 24px rgba(240,147,43,0.4); +} +.start-btn:disabled { opacity: 0.45; cursor: not-allowed; } +.start-btn:active:not(:disabled) { transform: scale(0.97); } +.how { margin-top: 22px; display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: #889; } +.credit { margin-top: 22px; font-size: 13px; color: #7cf6ff; font-weight: 600; } +.api-key-section { margin-top: 18px; text-align: left; max-width: 380px; margin-left: auto; margin-right: auto; } +.api-key-section label { display: block; font-size: 13px; font-weight: 700; color: #cdd; margin-bottom: 6px; } +#api-key-input { + width: 100%; padding: 10px 12px; border-radius: 10px; font-size: 14px; + background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.15); + color: #fff; outline: none; +} +#api-key-input:focus { border-color: rgba(124,246,255,0.5); } +.api-key-hint { font-size: 11px; color: #778; margin-top: 6px; line-height: 1.4; } +.credit-small, .credit { letter-spacing: 0.3px; } diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000000000000000000000000000000000000..1639bc9dcb7f27fc2ec6c0b63dfc2ef7347b5429 --- /dev/null +++ b/static/index.html @@ -0,0 +1,168 @@ +๏ปฟ + +
+ + + + + +Broadcast an order to the whole crew. Everyone will respond in character.
+A living AI colony on the Moon. Talk to your crew, gather resources, and build the mega-projects.
+ + +Paste your own key for smarter AI conversations. Without it, crew will still talk using built-in responses.
+${m.desc}
+Lunar Village is a SmallVill-style AI colony simulation set on the Moon. + You are the Colony Commander, managing a crew of 10 unique characters who live, work, fight, and talk using AI (DeepSeek).
+Gather resources, build mega-projects, manage your crew's health and morale, and watch the colony come alive.
+Created by Andy Kong
+ `; + + const howToPlay = ` +If food runs out, all crew lose HP. Keep production going!
+ `; + + const combat = ` +When two or more crew idle at the Arena, they spar automatically.
+