frontend/farm_designer/map/easter_eggs/bugs.tsx
import React from "react";
import { transformXY } from "../util";
import { MapTransformProps, BotSize } from "../interfaces";
import { random, range, some, clamp, sample } from "lodash";
import { getEggStatus, setEggStatus, EggKeys } from "./status";
import { t } from "../../../i18next_wrapper";
import { Row, Col, ToggleButton } from "../../../ui";
import { BUGS, FilePath, Bug as BugSlug } from "../../../internal_urls";
import { showByEveryTerm } from "../../../settings";
export interface BugsProps {
mapTransformProps: MapTransformProps;
botSize: BotSize;
}
type Bug = {
id: number,
x: number,
y: number,
r: number,
hp: number,
alive: boolean,
slug: BugSlug,
};
interface BugsState {
bugs: Bug[];
startTime: number;
}
export function showBugResetButton() {
return getEggStatus(EggKeys.BRING_ON_THE_BUGS) === "true" &&
getEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE) === "false";
}
export function showBugs() {
return getEggStatus(EggKeys.BRING_ON_THE_BUGS) === "true" &&
getEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE) !== "false";
}
export function resetBugs() {
setEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE, "true");
}
function getBugTime() {
return getEggStatus(EggKeys.LAST_BUG_TIME);
}
export class Bugs extends React.Component<BugsProps, BugsState> {
state: BugsState = { bugs: [], startTime: NaN };
componentDidMount() {
this.setState({
bugs: range(10).map(id => ({
id,
x: random(0, this.xMax),
y: random(0, this.yMax),
r: random(25, 100),
hp: 100,
alive: true,
slug: sample(BUGS) as BugSlug,
})),
startTime: this.seconds
});
}
get seconds() { return Math.floor(new Date().getTime() / 1000); }
get elapsedTime() { return this.seconds - this.state.startTime; }
onClick = (id: number) => {
const bugs = this.state.bugs;
if (bugs[id].r > 100 && bugs[id].hp > 50) {
bugs[id].hp = 50;
} else {
bugs[id].hp = 50;
bugs[id].alive = false;
}
bugs.map(b => {
if (b.alive) {
b.x = clamp(b.x + random(-100, 100), 0, this.xMax);
b.y = clamp(b.y + random(-100, 100), 0, this.yMax);
b.r = clamp(b.r + random(0, 10), 0, 150);
}
});
if (!some(bugs, "alive")) {
setEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE, "false");
setEggStatus(EggKeys.LAST_BUG_TIME, "" + this.elapsedTime);
}
this.forceUpdate();
};
get xMax() { return this.props.botSize.x.value; }
get yMax() { return this.props.botSize.y.value; }
render() {
const toQ = (ox: number, oy: number) =>
transformXY(ox, oy, this.props.mapTransformProps);
return <g id="bugs">
<filter id="grayscale">
<feColorMatrix type="saturate" values="0" />
</filter>
{this.state.bugs.map(bug => {
const { qx, qy } = toQ(bug.x, bug.y);
return <image
key={Object.values(bug).join("-")}
className={`bug ${bug.alive ? "" : "dead"}`}
filter={bug.alive ? "" : "url(#grayscale)"}
opacity={bug.hp / 100}
xlinkHref={FilePath.bug(bug.slug)}
onClick={() => this.onClick(bug.id)}
height={bug.r * 2}
width={bug.r * 2}
x={qx - bug.r}
y={qy - bug.r} />;
})}
</g>;
}
}
export const BugsControls = () =>
showBugResetButton()
? <div className="more-bugs">
<button
className="fb-button green"
title={t("more bugs!")}
onClick={resetBugs}>
{t("more bugs!")}
</button>
{getBugTime() &&
<p>
{t("{{seconds}} seconds!", { seconds: getBugTime() })}
</p>}
</div>
: <div className={"no-bugs"} />;
const Setting = (title: string, key: string, value: string) => {
const on = localStorage.getItem(key) == value;
return <div className={"setting"}>
<Row>
<Col xs={9}>
<label>{title}</label>
</Col>
<Col xs={3}>
<ToggleButton
toggleValue={on}
toggleAction={() => localStorage.setItem(key, on ? "" : value)} />
</Col>
</Row>
</div>;
};
export const ExtraSettings = (searchTerm: string) => {
return showByEveryTerm("surprise", searchTerm) &&
<div className={"settings"}>
{Setting("Bug Attack", EggKeys.BRING_ON_THE_BUGS, "true")}
</div>;
};