forked from BibliothecaDAO/eternum
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fdf1936
commit 0137c94
Showing
18 changed files
with
57,189 additions
and
56,357 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
216 changes: 216 additions & 0 deletions
216
client/src/components/cityview/realm/combat/defence/AttackHistory.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
import clsx from "clsx"; | ||
import { CombatResultInterface, Winner } from "../../../../../hooks/store/useCombatHistoryStore"; | ||
import { getComponentValue } from "@latticexyz/recs"; | ||
import { divideByPrecision, getEntityIdFromKeys } from "../../../../../utils/utils"; | ||
import { useDojo } from "../../../../../DojoContext"; | ||
import { getRealmNameById, getRealmOrderNameById } from "../../../../../utils/realms"; | ||
import { OrderIcon } from "../../../../../elements/OrderIcon"; | ||
import { useMemo } from "react"; | ||
import useUIStore from "../../../../../hooks/store/useUIStore"; | ||
// import ProgressBar from "../../../../../elements/ProgressBar"; | ||
import { ResourceCost } from "../../../../../elements/ResourceCost"; | ||
import useBlockchainStore from "../../../../../hooks/store/useBlockchainStore"; | ||
import { formatSecondsLeftInDaysHours } from "../../labor/laborUtils"; | ||
|
||
type AttackHistoryProps = { | ||
combatResult: CombatResultInterface; | ||
} & React.HTMLAttributes<HTMLDivElement>; | ||
|
||
export const AttackHistory = ({ combatResult, ...props }: AttackHistoryProps) => { | ||
const { | ||
setup: { | ||
components: { Realm, Quantity, Attack, Health, Defence }, | ||
}, | ||
} = useDojo(); | ||
|
||
const { attackerRealmEntityId, attackingEntityIds, stolenResources, winner, damage, attackTimestamp } = combatResult; | ||
|
||
const nextBlockTimestamp = useBlockchainStore((state) => state.nextBlockTimestamp); | ||
|
||
const setTooltip = useUIStore((state) => state.setTooltip); | ||
|
||
let { realm_id: attackerRealmId } = getComponentValue(Realm, getEntityIdFromKeys([BigInt(attackerRealmEntityId)])); | ||
let attackerName = attackerRealmId ? getRealmNameById(attackerRealmId) : undefined; | ||
|
||
const attackerTotalSoldiers = useMemo(() => { | ||
let total = 0; | ||
for (const id of attackingEntityIds) { | ||
let { value } = getComponentValue(Quantity, getEntityIdFromKeys([BigInt(id)])); | ||
total += value; | ||
} | ||
return total; | ||
}, [attackingEntityIds]); | ||
|
||
const attackerTotalAttack = useMemo(() => { | ||
let total = 0; | ||
for (const id of attackingEntityIds) { | ||
let { value } = getComponentValue(Attack, getEntityIdFromKeys([BigInt(id)])); | ||
total += value; | ||
} | ||
return total; | ||
}, [attackingEntityIds]); | ||
|
||
const attackerTotalHealth = useMemo(() => { | ||
let total = 0; | ||
for (const id of attackingEntityIds) { | ||
let { value } = getComponentValue(Health, getEntityIdFromKeys([BigInt(id)])); | ||
total += value; | ||
} | ||
return total; | ||
}, [attackingEntityIds]); | ||
|
||
const attackerTotalDefence = useMemo(() => { | ||
let total = 0; | ||
for (const id of attackingEntityIds) { | ||
let { value } = getComponentValue(Defence, getEntityIdFromKeys([BigInt(id)])); | ||
total += value; | ||
} | ||
return total; | ||
}, [attackingEntityIds]); | ||
|
||
return ( | ||
<div | ||
className={clsx( | ||
"flex flex-col w-full mb-1 pb-1 pr-1 border rounded-md border-gray-gold text-xxs text-gray-gold", | ||
props.className, | ||
)} | ||
onClick={props.onClick} | ||
> | ||
<div className="flex items-center text-xxs"> | ||
{winner && ( | ||
<div | ||
className={clsx( | ||
"flex items-center p-1 border text-light-pink rounded-br-md rounded-tl-md border-gray-gold", | ||
winner === Winner.Target && "!text-order-brilliance !border-order-brilliance", | ||
winner === Winner.Attacker && "!text-order-giants !border-order-giants", | ||
)} | ||
> | ||
{winner === Winner.Target && "Failed"} | ||
{winner === Winner.Attacker && "Success"} | ||
</div> | ||
)} | ||
<div className="flex items-center pt-1 ml-1 -mt-2"> | ||
{stolenResources.length === 0 && attackerRealmId && ( | ||
<div className="flex items-center ml-1"> | ||
<div className="flex items-center ml-1 mr-1 text-gold"> | ||
<OrderIcon order={getRealmOrderNameById(attackerRealmId)} className="mr-1" size="xxs" /> | ||
{attackerName} | ||
</div> | ||
{winner === Winner.Attacker && ( | ||
<span className="italic text-light-pink">{`Attacked with ${attackerTotalSoldiers} battalions`}</span> | ||
)} | ||
{winner === Winner.Target && ( | ||
<span className="italic text-light-pink">{`Failed to attack with ${attackerTotalSoldiers} battalions`}</span> | ||
)} | ||
</div> | ||
)} | ||
{stolenResources.length > 0 && attackerRealmId && ( | ||
<div className="flex items-center ml-1"> | ||
<div className="flex items-center ml-1 mr-1 text-gold"> | ||
<OrderIcon order={getRealmOrderNameById(attackerRealmId)} className="mr-1" size="xxs" /> | ||
{attackerName} | ||
</div> | ||
<span className="italic text-light-pink">{`Has stolen ${stolenResources.length} resources`}</span> | ||
</div> | ||
)} | ||
</div> | ||
{attackTimestamp && nextBlockTimestamp && ( | ||
<div className="flex ml-auto -mt-1 italic text-light-pink"> | ||
{formatSecondsLeftInDaysHours(nextBlockTimestamp - attackTimestamp)} | ||
</div> | ||
)} | ||
</div> | ||
<div className="flex flex-col mt-2 space-y-2"> | ||
<div className="flex relative justify-between text-xxs text-lightest w-full"> | ||
<div className="flex items-center"> | ||
<div className="flex items-center h-6 mr-2"> | ||
<img src="/images/units/troop-icon.png" className="h-[28px]" /> | ||
<div className="flex ml-1 text-center"> | ||
<div className="bold mr-1">x{attackerTotalSoldiers}</div> | ||
Battalions | ||
</div> | ||
</div> | ||
</div> | ||
<div className="flex absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 items-center"> | ||
<div | ||
className="flex items-center h-6 mr-2" | ||
onMouseEnter={() => | ||
setTooltip({ | ||
position: "top", | ||
content: ( | ||
<> | ||
<p className="whitespace-nowrap">Attack power</p> | ||
</> | ||
), | ||
}) | ||
} | ||
onMouseLeave={() => setTooltip(null)} | ||
> | ||
<img src="/images/icons/attack.png" className="h-full" /> | ||
<div className="flex flex-col ml-1 text-center"> | ||
<div className="bold ">{attackerTotalAttack}</div> | ||
</div> | ||
</div> | ||
<div | ||
className="flex items-center h-6 mr-2" | ||
onMouseEnter={() => | ||
setTooltip({ | ||
position: "top", | ||
content: ( | ||
<> | ||
<p className="whitespace-nowrap">Defence power</p> | ||
</> | ||
), | ||
}) | ||
} | ||
onMouseLeave={() => setTooltip(null)} | ||
> | ||
<img src="/images/icons/defence.png" className="h-full" /> | ||
<div className="flex flex-col ml-1 text-center"> | ||
<div className="bold ">{attackerTotalDefence}</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div className="flex items-center"> | ||
<div className="text-order-brilliance">{attackerTotalHealth && attackerTotalHealth.toLocaleString()}</div> | ||
/ {10 * attackerTotalSoldiers} HP | ||
</div> | ||
</div> | ||
{/* {attackerTotalHealth !== undefined && ( | ||
<div className="grid grid-cols-12 gap-0.5"> | ||
<ProgressBar | ||
containerClassName="col-span-12 !bg-order-giants" | ||
rounded | ||
progress={(attackerTotalHealth / (attackerTotalSoldiers * 10)) * 100} | ||
/> | ||
</div> | ||
)} */} | ||
<div className="flex items-center justify-between mt-[8px] text-xxs"> | ||
{stolenResources && stolenResources.length > 0 && ( | ||
<div className="flex justify-center items-center space-x-1 flex-wrap"> | ||
{stolenResources.map( | ||
(resource) => | ||
resource && ( | ||
<ResourceCost | ||
key={resource.resourceId} | ||
type="vertical" | ||
color="text-order-brilliance" | ||
resourceId={resource.resourceId} | ||
amount={divideByPrecision(resource.amount)} | ||
/> | ||
), | ||
)} | ||
</div> | ||
)} | ||
{damage && damage > 0 && ( | ||
<div className="flex justify-center ml-2 mb-1 items-center space-x-1 flex-wrap"> | ||
{winner === Winner.Attacker && <span className="text-white"> Attacker gave</span>} | ||
{winner === Winner.Target && <span className="text-white"> Attacker received</span>} | ||
<span className="text-anger-light"> -{damage} Damage</span> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; |
22 changes: 22 additions & 0 deletions
22
client/src/components/cityview/realm/combat/defence/AttackHistoryPanel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import useCombatHistoryStore from "../../../../../hooks/store/useCombatHistoryStore"; | ||
import { AttackHistory } from "./AttackHistory"; | ||
|
||
type AttackHistoryPanelProps = {}; | ||
|
||
export const AttackHistoryPanel = ({}: AttackHistoryPanelProps) => { | ||
const combatHistory = useCombatHistoryStore((state) => state.combatHistory); | ||
|
||
return ( | ||
<div className="relative flex flex-col p-2 min-h-[120px]"> | ||
<div className="flex flex-col"> | ||
{combatHistory.length > 0 && ( | ||
<> | ||
{combatHistory.map((combatResult, i) => ( | ||
<AttackHistory key={i} combatResult={combatResult} /> | ||
))} | ||
</> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; |
118 changes: 118 additions & 0 deletions
118
client/src/components/cityview/realm/combat/defence/AttacksComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import { useEffect, useMemo, useState } from "react"; | ||
import { Tabs } from "../../../../../elements/tab"; | ||
import useUIStore from "../../../../../hooks/store/useUIStore"; | ||
import { useRoute, useLocation } from "wouter"; | ||
import useRealmStore from "../../../../../hooks/store/useRealmStore"; | ||
import { EnnemyRaidersPanel } from "./EnnemyRaidsPanel"; | ||
import { AttackHistoryPanel } from "./AttackHistoryPanel"; | ||
|
||
export type Order = { | ||
orderId: number; | ||
counterpartyOrderId: number; | ||
tradeId: number; | ||
}; | ||
|
||
type AttacksComponentProps = {}; | ||
|
||
export const AttacksComponent = ({}: AttacksComponentProps) => { | ||
const [selectedTab, setSelectedTab] = useState(0); | ||
const { realmEntityId } = useRealmStore(); | ||
|
||
const moveCameraToMarketView = useUIStore((state) => state.moveCameraToMarketView); | ||
const moveCameraToCaravansView = useUIStore((state) => state.moveCameraToCaravansView); | ||
const setTooltip = useUIStore((state) => state.setTooltip); | ||
|
||
// @ts-ignore | ||
const [location, setLocation] = useLocation(); | ||
// @ts-ignore | ||
const [match, params]: any = useRoute("/realm/:id/:tab"); | ||
|
||
useEffect(() => { | ||
if ([0, 1, 2].includes(selectedTab)) { | ||
moveCameraToMarketView(); | ||
} else if ([3, 4].includes(selectedTab)) { | ||
moveCameraToCaravansView(); | ||
} | ||
}, [selectedTab]); | ||
|
||
useEffect(() => { | ||
const tabIndex = tabs.findIndex((tab) => tab.key === params?.tab); | ||
if (tabIndex >= 0) { | ||
setSelectedTab(tabIndex); | ||
} | ||
}, [params]); | ||
|
||
const tabs = useMemo( | ||
() => [ | ||
{ | ||
key: "ennemy-raiders", | ||
label: ( | ||
<div | ||
onMouseEnter={() => | ||
setTooltip({ | ||
position: "bottom", | ||
content: ( | ||
<> | ||
<p className="whitespace-nowrap">Ennemies on your realm</p> | ||
</> | ||
), | ||
}) | ||
} | ||
onMouseLeave={() => setTooltip(null)} | ||
className="flex relative group flex-col items-center" | ||
> | ||
<div> Current Attacks </div> | ||
</div> | ||
), | ||
component: <EnnemyRaidersPanel />, | ||
}, | ||
{ | ||
key: "attack-history", | ||
label: ( | ||
<div | ||
onMouseEnter={() => | ||
setTooltip({ | ||
position: "bottom", | ||
content: ( | ||
<> | ||
<p className="whitespace-nowrap">Previous attacks</p> | ||
</> | ||
), | ||
}) | ||
} | ||
onMouseLeave={() => setTooltip(null)} | ||
className="flex relative group flex-col items-center" | ||
> | ||
<div>Attack History</div> | ||
</div> | ||
), | ||
component: <AttackHistoryPanel />, | ||
}, | ||
], | ||
[selectedTab], | ||
); | ||
|
||
return ( | ||
<> | ||
<Tabs | ||
selectedIndex={selectedTab} | ||
onChange={(index: any) => setLocation(`/realm/${realmEntityId}/${tabs[index].key}`)} | ||
variant="default" | ||
className="h-full" | ||
> | ||
<Tabs.List> | ||
{tabs.map((tab, index) => ( | ||
<Tabs.Tab key={index}>{tab.label}</Tabs.Tab> | ||
))} | ||
</Tabs.List> | ||
<Tabs.Panels className="overflow-hidden"> | ||
{tabs.map((tab, index) => ( | ||
<Tabs.Panel key={index}>{tab.component}</Tabs.Panel> | ||
))} | ||
</Tabs.Panels> | ||
</Tabs> | ||
</> | ||
); | ||
}; | ||
|
||
export default AttacksComponent; |
Oops, something went wrong.