diff --git a/app/src/components/MarchingBand.tsx b/app/src/components/MarchingBand.tsx
new file mode 100644
index 0000000..0bc09cb
--- /dev/null
+++ b/app/src/components/MarchingBand.tsx
@@ -0,0 +1,115 @@
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import styles from '../styles/Army.module.css';
+
+interface MarchingGroupType {
+ id: number,
+ people: [number, number][]
+ removeGroup: (id: number) => void
+}
+
+const MarchingGroup = ({ people, id, removeGroup }: MarchingGroupType) => {
+ useEffect(() => {
+ const destroyTimeout = setTimeout(() => {
+ removeGroup(id)
+ }, 18000);
+ return () => clearTimeout(destroyTimeout)
+ }, [id, removeGroup])
+ const groupHtml = useMemo(() => {
+ return
+ {people.map(([personStatus, role], index) => {
+ const cssRole = intToRole(role);
+ const cssStatus = intToStatus(personStatus);
+ return
+ })}
+
+ }, [people, id])
+ return groupHtml
+}
+
+const MarchingBand = () => {
+ const [groups, setGroups] = useState([]);
+ const removeGroup = useCallback((id: number) => {
+ setGroups(p => p.filter(p => p.id !== id));
+ }, [setGroups])
+ const addGroup = useCallback(() => {
+ const nPeople = getRandomInt(2, 4);
+ const people: [number, number][] = []
+ for (let i = 0; i < nPeople; i++) {
+ people.push([getRandomInt(0, 3), getRandomInt(0, 14)])
+ }
+ setGroups(g => [...g, { id: Math.random(), people, removeGroup }]);
+ }, [removeGroup])
+
+ useEffect(() => {
+ const addingInterval = setInterval(() => {
+ addGroup()
+ }, 8000)
+ return () => clearInterval(addingInterval)
+ }, [addGroup])
+
+ return
+ {groups.map(({ id, people }) =>
+ )}
+
+}
+
+const getRandomInt = (min: number, max: number) => Math.floor(Math.random() * (max + 1 - min) + min)
+
+const intToRole = (val: number) => {
+ switch (val) {
+ case 0:
+ return styles.alchemist
+ case 1:
+ return styles.archer
+ case 2:
+ return styles.cleric
+ case 3:
+ return styles.druid
+ case 4:
+ return styles.dwarf
+ case 5:
+ return styles.monk
+ case 6:
+ return styles.necromancer
+ case 7:
+ return styles.paladin
+ case 8:
+ return styles.ranger
+ case 9:
+ return styles.rogue
+ case 10:
+ return styles.scribe
+ case 11:
+ return styles.warrior
+ case 12:
+ return styles.wizard
+ case 13:
+ return styles.healer
+ case 14:
+ return styles.hunter
+ default:
+ return styles.wizard
+ }
+}
+const intToStatus = (val: number) => {
+ switch (val) {
+ case 0:
+ return styles.moloch_denier;
+ case 1:
+ return styles.apprentice;
+ case 2:
+ return styles.anointed;
+ case 3:
+ return styles.champion;
+ default:
+ return styles.moloch_denier;
+ }
+}
+
+export default MarchingBand
+
diff --git a/app/src/components/Scene.tsx b/app/src/components/Scene.tsx
index 4702daa..1561e61 100644
--- a/app/src/components/Scene.tsx
+++ b/app/src/components/Scene.tsx
@@ -2,6 +2,7 @@ import React from "react"
import styles from '../styles/Background.module.css';
import Tower from "./Tower";
import Army from "./Army";
+import MarchingBand from "./MarchingBand";
const Scene = () => {
return
@@ -11,6 +12,7 @@ const Scene = () => {
+ {/*
*/}
diff --git a/app/src/styles/Army.module.css b/app/src/styles/Army.module.css
index bfdb598..1bf445c 100644
--- a/app/src/styles/Army.module.css
+++ b/app/src/styles/Army.module.css
@@ -1,3 +1,11 @@
+.marchingBand {
+ position: absolute;
+ left: 22px;
+ right: 22px;
+ bottom: 22px;
+ top: 22px;
+ overflow: hidden;
+}
.army-gathering {
position: absolute;
bottom: 22px;
@@ -13,6 +21,45 @@
background-repeat: no-repeat;
transform-origin: bottom center;
}
+.marchingGroup {
+ position: absolute;
+ user-select: none;
+ pointer-events: none;
+ left: 0;
+ bottom: 84px;
+ animation: marching 20s linear;
+ width: 200px;
+ & > div {
+ position: absolute;
+ }
+ & > div:nth-child(1) {
+ left: 30px;
+ animation:
+ marchingPerson 20s linear,
+ marchingPersonSkew 1s ease infinite,
+ marchingPersonLeft1 20s linear;
+ }
+ & > div:nth-child(2) {
+ left: 0px;
+ animation:
+ marchingPerson 20s linear,
+ marchingPersonSkew 1s ease infinite;
+ }
+ & > div:nth-child(3) {
+ left: -30px;
+ animation:
+ marchingPerson 20s linear,
+ marchingPersonSkew 1s ease infinite,
+ marchingPersonLeft3 20s linear;
+ }
+ & > div:nth-child(4) {
+ left: 60px;
+ animation:
+ marchingPerson 20s linear,
+ marchingPersonSkew 1s ease infinite,
+ marchingPersonLeft4 20s linear;
+ }
+}
.tavern_keeper {
background-image: url("/roles/tavern-keeper.svg");
}
@@ -122,3 +169,156 @@
font-size: 0.8rem;
user-select: none;
}
+
+@keyframes marching {
+ 0% {
+ transform: translate(-100px, -84px);
+ }
+ 8% {
+ /* approaches fire */
+ transform: translate(72px, -84px);
+ }
+ 15% {
+ /* approaches road */
+ transform: translate(152px, -174px);
+ }
+ 25% {
+ /* first road turn */
+ transform: translate(122px, -284px);
+ }
+ 45% {
+ /* second road turn */
+ transform: translate(256px, -374px);
+ }
+ 75% {
+ /* third road turn */
+ transform: translate(159px, -416px);
+ }
+ 100% {
+ /* vanishes into distance */
+ transform: translate(180px, -425px);
+ }
+}
+
+@keyframes marchingPerson {
+ 0% {
+ background-size: 100% 100%;
+ }
+ 8% {
+ /* approaches fire */
+ }
+ 15% {
+ /* approaches road */
+ background-size: 95% 95%;
+ }
+ 25% {
+ /* first road turn */
+ background-size: 80% 80%;
+ }
+ 45% {
+ /* second road turn */
+ background-size: 65% 65%;
+ }
+ 75% {
+ /* third road turn */
+ background-size: 15% 15%;
+ }
+ 100% {
+ /* vanishes into distance */
+ background-size: 2% 2%;
+ }
+}
+
+@keyframes marchingPersonLeft1 {
+ 0% {
+ left: 30px;
+ }
+ 15% {
+ /* approaches road */
+ left: calc(30px * 0.95);
+ }
+ 25% {
+ /* first road turn */
+ left: calc(30px * 0.8);
+ }
+ 45% {
+ /* second road turn */
+ left: calc(30px * 0.65);
+ }
+ 75% {
+ /* third road turn */
+ left: calc(30px * 0.15);
+ }
+ 100% {
+ /* vanishes into distance */
+ left: calc(30px * 0.02);
+ }
+}
+
+@keyframes marchingPersonLeft3 {
+ 0% {
+ left: -30px;
+ }
+ 15% {
+ /* approaches road */
+ left: calc(-30px * 0.95);
+ }
+ 25% {
+ /* first road turn */
+ left: calc(-30px * 0.8);
+ }
+ 45% {
+ /* second road turn */
+ left: calc(-30px * 0.65);
+ }
+ 75% {
+ /* third road turn */
+ left: calc(-30px * 0.15);
+ }
+ 100% {
+ /* vanishes into distance */
+ left: calc(-30px * 0.02);
+ }
+}
+
+@keyframes marchingPersonLeft4 {
+ 0% {
+ left: 60px;
+ }
+ 15% {
+ /* approaches road */
+ left: calc(60px * 0.95);
+ }
+ 25% {
+ /* first road turn */
+ left: calc(60px * 0.8);
+ }
+ 45% {
+ /* second road turn */
+ left: calc(60px * 0.65);
+ }
+ 75% {
+ /* third road turn */
+ left: calc(60px * 0.15);
+ }
+ 100% {
+ /* vanishes into distance */
+ left: calc(60px * 0.02);
+ }
+}
+
+@keyframes marchingPersonSkew {
+ 0%,
+ 100% {
+ transform: skew(0deg, 0deg);
+ }
+ 25% {
+ transform: skew(5deg, -5deg);
+ }
+ 50% {
+ transform: skew(0deg, 0deg);
+ }
+ 75% {
+ transform: skew(-5deg, 5deg);
+ }
+}
diff --git a/deploy_contract.sh b/deploy_contract.sh
index 1d29a44..8dc4b9a 100755
--- a/deploy_contract.sh
+++ b/deploy_contract.sh
@@ -1,3 +1,4 @@
#!/bin/sh
cast rpc anvil_setBalance 0x3295CCA2d922c637d35b258fc6c9C7e471803b45 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545
forge script script/RaidGeld.s.sol:RaidGeldScript --rpc-url 127.0.0.1:8545 --broadcast --private-key $DEV_PRIVATE_KEY
+cast rpc anvil_mine