diff --git a/content/diplomacy/gift-area-planets/index.md b/content/diplomacy/gift-area-planets/index.md
new file mode 100644
index 00000000..958e5073
--- /dev/null
+++ b/content/diplomacy/gift-area-planets/index.md
@@ -0,0 +1,6 @@
+---
+title: Gift Area Planets
+date: 2021-10-10T09:34:57+08:00
+subtitle: Gift the planet(s) circled with level filter and support gift single planet, gift range planet(s) and gift all planet(s) :)
+version: 0.6.5
+---
diff --git a/content/diplomacy/gift-area-planets/plugin.js b/content/diplomacy/gift-area-planets/plugin.js
new file mode 100644
index 00000000..91ac3d29
--- /dev/null
+++ b/content/diplomacy/gift-area-planets/plugin.js
@@ -0,0 +1,475 @@
+//
+// Gift Area Planets
+//
+// author: https://twitter.com/ddy_mainland
+//
+// Gift the planet(s) with colorful circle(s) on the map.
+// You can choose one of the receiver's planets and determine the address of just in the address.
+// For planet filter, this plugin supports level filter and have three modes:
+// set Single Planet, set Range Planet(s) and set All Planet(s).
+//
+//
+
+
+import { PlanetLevel, PlanetType, PlanetTypeNames } from
+ "https://cdn.skypack.dev/@darkforest_eth/types";
+
+import { html, render, useState } from
+ "https://unpkg.com/htm@3/preact/standalone.module.js";
+
+import { getPlayerColor } from
+ "https://cdn.skypack.dev/@darkforest_eth/procedural";
+
+let minLevel = 4;
+let maxLevel = 9;
+
+let planetRange = {
+ beginCoords: null,
+ endCoords: null,
+};
+
+const CursorMode = {
+ SINGLE: 1,
+ RANGE: 2,
+ ALL: 3
+};
+
+let showPlanetList = [];
+let cursorMode = CursorMode.ALL;
+
+function clearRangeCoords() {
+ planetRange = {
+ beginCoords: null,
+ endCoords: null,
+ };
+}
+
+function setCursorMode(mode) {
+// console.log("Set Cursor Mode to: ", mode);
+ switch (mode) {
+ case CursorMode.RANGE:
+ clearRangeCoords();
+ cursorMode = CursorMode.RANGE;
+ break;
+ case CursorMode.SINGLE:
+ clearRangeCoords();
+ cursorMode = CursorMode.SINGLE;
+ break;
+ default:
+ clearRangeCoords();
+ cursorMode = CursorMode.ALL;
+ }
+}
+
+const PLANET_LEVELS = Object.values(PlanetLevel).map((level) => ({
+ value: level,
+ text: level.toString(),
+}));
+
+function drawRound(ctx, p, color, alpha) {
+ if (!p) return '(???,???)';
+ const viewport = ui.getViewport();
+ ctx.strokeStyle = color;
+
+ ctx.globalAlpha = alpha;
+ ctx.lineWidth = 2;
+ const { x, y } = viewport.worldToCanvasCoords(p.location.coords);
+ const range = p.range * 0.01 * 20;
+ const trueRange = viewport.worldToCanvasDist(range);
+ ctx.beginPath();
+ // ctx.setLineDash([10,10]);
+ ctx.arc(x, y, trueRange, 0, 2 * Math.PI);
+ ctx.stroke();
+ return `(${p.location.coords.x},${p.location.coords.y})`
+}
+
+function drawRectangle(ctx, coordsA, coordsB, color) {
+ if (coordsA && coordsB) {
+ const viewport = ui.getViewport();
+ let beginX = Math.min(coordsA.x, coordsB.x);
+ let beginY = Math.min(coordsA.y, coordsB.y);
+ let endX = Math.max(coordsA.x, coordsB.x);
+ let endY = Math.max(coordsA.y, coordsB.y);
+ let width = endX - beginX;
+ let height = endY - beginY;
+
+ ctx.save();
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.strokeRect(
+ viewport.worldToCanvasX(beginX),
+ viewport.worldToCanvasY(endY),
+ viewport.worldToCanvasDist(width),
+ viewport.worldToCanvasDist(height)
+ );
+ ctx.restore();
+ }
+}
+
+
+function refreshPlanetList() {
+ // console.log("refreshPlanet");
+ if (cursorMode === CursorMode.ALL) {
+ showPlanetList = [];
+ const planets = df.getMyPlanets();
+ for (let i in planets) {
+ let p = planets[i];
+ if (!p?.location?.coords) continue;
+ if (p.planetLevel < minLevel) continue;
+ if (p.planetLevel > maxLevel) continue;
+ showPlanetList.push(p);
+ }
+ return;
+ } else if (cursorMode === CursorMode.RANGE) {
+ if (planetRange.beginCoords === null) return;
+ if (planetRange.endCoords === null) return;
+ showPlanetList = [];
+ let coordsA = planetRange.beginCoords;
+ let coordsB = planetRange.endCoords;
+ let beginX = Math.min(coordsA.x, coordsB.x);
+ let beginY = Math.min(coordsA.y, coordsB.y);
+ let endX = Math.max(coordsA.x, coordsB.x);
+ let endY = Math.max(coordsA.y, coordsB.y);
+ const planets = df.getMyPlanets();
+ for (let i in planets) {
+ let p = planets[i];
+ if (!p?.location?.coords) continue;
+ if (p.planetLevel < minLevel) continue;
+ if (p.planetLevel > maxLevel) continue;
+ let coords = p.location.coords;
+ if (coords.x >= beginX && coords.y >= beginY && coords.x <= endX && coords.y <= endY) {
+ showPlanetList.push(p);
+ }
+ }
+ }
+}
+
+function giftAreaPlanets() {
+ const [toAddress, setToAddress] = useState(undefined);
+ const [inMinLevel, setInMinLevel] = useState(minLevel);
+ const [inMaxLevel, setInMaxLevel] = useState(maxLevel);
+ const [selectInfo, setSelectInfo] =
+ useState("select the planet(s) you want to share");
+ const [giftInfo, setGiftInfo] = useState('');
+
+ let divStyle = {
+ textAlign: 'center',
+ justifyContent: "space-around",
+ width: "100%",
+ marginTop: "10px",
+ };
+
+ let warningStyle = {
+ color: 'red'
+ };
+
+ let infoStyle = {
+ color: '#F4D03F '
+ };
+
+ let myAccountComponent =
+ df.account == undefined ?
+ html`
You Are not log in
` :
+ html`
+ your address is :
+
${df.account}
+
`;
+
+
+ let [input, setInput] = useState(undefined);
+
+ let toAddressPart = toAddress === undefined ?
+ html`not choose yet
` :
+ html`${toAddress}
`;
+
+ let toAddressComponent =
+ html`
+
+ {
+ setInput(e.target.value);
+ }}>
+
+
+
+
+
+
+
the account who get your planet(s) is
+
+ ${toAddressPart}
+
+
+
`;
+
+ let selectStyle = {
+ background: "rgb(8,8,8)",
+ width: "100px",
+ padding: "3px 5px",
+ border: "1px solid white",
+ borderRadius: "3px",
+ };
+
+ const minLevelSelect = html`
+ `;
+
+ const maxLevelSelect = html`
+ `;
+
+ const selectLevelComponent = html`
+
+
choose the planetLevel
+
+ ${minLevelSelect}
+ ${' '}
+ ${maxLevelSelect}
+
+
the level you choose is [${minLevel},${maxLevel}]
+
+ `;
+
+ function selectSinglePlanet() {
+ // console.log("Select Single Planet");
+ setCursorMode(CursorMode.SINGLE);
+ showPlanetList = [];
+ setSelectInfo("please click one planet to share");
+ setGiftInfo('');
+ return;
+ }
+
+ let selectSinglePlanetButton = html`
+
+
+
+ `;
+
+ function selectRangePlanet() {
+ // console.log("Select Range Planet");
+ setCursorMode(CursorMode.RANGE);
+ showPlanetList = [];
+ setSelectInfo("determine the area of planet(s) with level filter");
+ setGiftInfo('');
+ return;
+ }
+
+
+ let selectRangeButton =
+ html`
+
+
+
+ `;
+
+ function selectAllPlanet() {
+ // console.log("Select All Planet");
+ setCursorMode(CursorMode.ALL);
+ showPlanetList = df.getMyPlanets();
+ setSelectInfo("determine all planet(s) with level filter");
+ setGiftInfo('');
+ }
+ let selectAllButton = html`
+
+
+
+ `;
+ const flexRow = {
+ display: "flex",
+ flexDirection: "row",
+ };
+
+ let selectComponent = html`
+
+ ${selectSinglePlanetButton}
+ ${selectRangeButton}
+ ${selectAllButton}
+
+ ${selectInfo}
+
`;
+
+ function giftPlanet() {
+ // console.log(showPlanetList);
+ for (let i in showPlanetList) {
+ let p = showPlanetList[i];
+ df.transferOwnership(p.locationId, toAddress);
+ }
+ setGiftInfo("the " + showPlanetList.length + " circled planet(s) will be shared");
+ }
+
+ let giftComponent = html`
+
+
+
${giftInfo}
+
`;
+
+ return html`
+
+ ${toAddressComponent}
+ ${selectLevelComponent}
+ ${selectComponent}
+ ${giftComponent}
+
`;
+
+}
+
+
+function App() {
+ return html`<${giftAreaPlanets} />`;
+}
+
+class Plugin {
+ constructor() {
+ minLevel = 4;
+ maxLevel = 9;
+ cursorMode === CursorMode.ALL;
+ showPlanetList = df.getMyPlanets();
+ refreshPlanetList();
+ this.container = null;
+ }
+
+ onClick = () => {
+ if (cursorMode === CursorMode.SINGLE) {
+
+ let p = ui.getSelectedPlanet();
+ if (p == undefined) return;
+ if (p.owner != df.account) return;
+ showPlanetList = [];
+ showPlanetList.push(p);
+
+
+ } else if (cursorMode === CursorMode.RANGE) {
+ let coords = ui.getHoveringOverCoords();
+ if (!coords) return;
+ if (planetRange.beginCoords == null) {
+ planetRange.beginCoords = coords;
+ return;
+ } else if (planetRange.endCoords == null) {
+ planetRange.endCoords = coords;
+ // console.log(planetRange);
+ refreshPlanetList();
+ } else {
+ //console.log(planetRange);
+ refreshPlanetList();
+ }
+ }else if (cursorMode === CursorMode.ALL){
+ refreshPlanetList();
+ }
+ }
+
+ draw(ctx) {
+ if (cursorMode === CursorMode.RANGE) {
+ let begin = planetRange.beginCoords;
+ let end = planetRange.endCoords || ui.getHoveringOverCoords();
+
+ drawRectangle(ctx, begin, end, "red");
+ if (begin != null && end != null) {
+ let coordsA = begin;//planetRange.beginCoords;
+ let coordsB = end;//planetRange.endCoords;
+ let beginX = Math.min(coordsA.x, coordsB.x);
+ let beginY = Math.min(coordsA.y, coordsB.y);
+ let endX = Math.max(coordsA.x, coordsB.x);
+ let endY = Math.max(coordsA.y, coordsB.y);
+
+ const planets = df.getMyPlanets();
+
+ if (minLevel > maxLevel) {
+ let tmp = minLevel;
+ minLevel = maxLevel;
+ maxLevel = tmp;
+ }
+
+
+ for (let i in planets) {
+ let p = planets[i];
+ if (!p?.location?.coords) continue;
+ if (p.planetLevel < minLevel) continue;
+ if (p.planetLevel > maxLevel) continue;
+
+ let coords = p.location.coords;
+ if (coords.x >= beginX && coords.y >= beginY && coords.x <= endX && coords.y <= endY) {
+
+ let color = getPlayerColor(p.owner);
+ drawRound(ctx, p, color, 0.7);
+ }
+ }
+ }
+ }
+ for (let i in showPlanetList) {
+ let p = showPlanetList[i];
+ let color = getPlayerColor(p.owner);
+ drawRound(ctx, p, color, 1);
+ }
+ }
+
+ async render(container) {
+ this.container = container;
+ container.style.width = "350px";
+ container.style.height = "420px";
+ window.addEventListener("click", this.onClick);
+ render(html`<${App} />`, container);
+ }
+
+ destroy() {
+ render(null, this.container);
+ }
+}
+
+export default Plugin;
+
+
+
+
+
diff --git a/content/diplomacy/gift-area-planets/screenshot.png b/content/diplomacy/gift-area-planets/screenshot.png
new file mode 100755
index 00000000..90c370c8
Binary files /dev/null and b/content/diplomacy/gift-area-planets/screenshot.png differ