import "./App.css";
import classnames from "classnames";
import React, { useCallback, useMemo, useState } from "react";
import UAParser from "ua-parser-js";
import { DebugTab } from "./components/DebugTab";
import { KeyboardControlComponent } from "./components/KeyboardControl";
import { NodeDetail } from "./components/NodeDetail";
import { PixiComponent } from "./components/PixiComponent";
import QuestProgress from "./components/QuestProgress";
import Sidebar from "./components/Sidebar";
import TabContent from "./components/TabContent";
import Tabs from "./components/Tabs";
import { UseGameStateContext } from "./contexts";
import { GameState } from "./data/GameState";
import { GameStateFactory } from "./game/GameStateFactory";
import { createQuest } from "./game/OnCreateQuest";
import { batchifySetState } from "./lib/util/batchify";
import { Lazy } from "./lib/util/misc";
import { updaterGenerator2 } from "./lib/util/updaterGenerator";
import { computeQuestEfficiencyPercent, remapQuestEfficiencyToGrade } from "./game/EfficiencyCalculator";
// TODO(bowei): on mobile, for either ios or android, when in portrait locked orientation, we want to serve a landscape
// experience - similar to a native app which is landscape locked.
// (on mobile in already landscape orientation, and in all desktop, serve ordinary orientation.)
// also note that android webapp supports manifest.json setting orientation, but not in the browser
// FOR NOW - ignore this
const browser = new UAParser().getBrowser();
let forceRotate = false;
if (
browser.name === "Mobile Safari" &&
window.innerWidth < window.innerHeight
) {
forceRotate = true;
}
const tabLabels = ["Quest Progress", "Node Details", "Debug"];
const initialGameState: Lazy<GameState> = new Lazy(() =>
new GameStateFactory({}).create()
);
function App() {
const [gameState, setGameState] = useState<GameState>(function factory() {
return initialGameState.get();
});
let [batchedSetGameState, fireBatch] = useMemo(
() => batchifySetState(setGameState),
[setGameState]
);
let updaters = useMemo(
() => updaterGenerator2(initialGameState.get(), batchedSetGameState),
[batchedSetGameState]
);
let createQuestCb = useCallback(() => createQuest(updaters), [
updaters,
]);
let tabViews: JSX.Element[] = [];
tabViews = [
<QuestProgress
spSpentThisQuest={gameState.playerSave.spSpentThisQuest}
createQuestCb={createQuestCb}
activeQuest={gameState.playerSave.activeQuest}
playerResourceAmounts={gameState.computed.playerResourceAmounts}
updaters={updaters.playerSave}
score={gameState.playerSave.score}
efficiencyGrade={remapQuestEfficiencyToGrade(computeQuestEfficiencyPercent(gameState.playerSave))}
questInitialAmount={gameState.playerSave.questInitialAmount}
/>,
<NodeDetail
selectedPointNode={gameState.playerUI.selectedPointNode}
allocatedPointNodeSet={gameState.playerSave.allocatedPointNodeSet}
worldGen={gameState.worldGen}
hasActiveQuest={gameState.playerSave.activeQuest !== undefined}
/>,
<DebugTab
selectedPointNode={gameState.playerUI.selectedPointNode}
allocatedPointNodeSet={gameState.playerSave.allocatedPointNodeSet}
worldGen={gameState.worldGen}
playerSave={gameState.playerSave}
computed={gameState.computed}
/>,
];
return (
<div className={classnames({ App: true, "force-landscape": forceRotate })}>
<UseGameStateContext.Provider value={[gameState, updaters, fireBatch]}>
<PixiComponent originalSetGameState={setGameState} />
<Sidebar>
<Tabs
value={gameState.playerUI.activeTab}
labels={tabLabels}
onChange={updaters.playerUI.activeTab.getUpdater()}
/>
{tabViews.map((component, i) => {
return (
<TabContent
key={i}
showContent={gameState.playerUI.activeTab === i}
>
{component}
</TabContent>
);
})}
</Sidebar>
</UseGameStateContext.Provider>
<KeyboardControlComponent
intent={gameState.intent}
updaters={updaters.intent}
></KeyboardControlComponent>
</div>
);
}
export default App;