{
14 | render() {
15 | let itemUseDescriptions = [];
16 | const { uses } = this.props.item;
17 | for (let use of uses) {
18 | if (use === Item.ItemUse.SKILL && uses.includes(Item.ItemUse.ASCENSION)) {
19 | itemUseDescriptions.push(ItemDescriptor.describeUse("skill & ascension"));
20 | continue;
21 | }
22 | if (use === Item.ItemUse.ASCENSION && uses.includes(Item.ItemUse.SKILL)) continue;
23 |
24 | itemUseDescriptions.push(ItemDescriptor.describeUse(use));
25 | }
26 | return (
27 |
28 | {mergeElements(
29 | itemUseDescriptions.map((use) => {use}),
30 | ", "
31 | )}
32 |
33 | );
34 | }
35 | }
36 |
37 | export default ItemUseDescription;
38 |
--------------------------------------------------------------------------------
/packages/db/src/Descriptor/Func/handleLinkageSection.tsx:
--------------------------------------------------------------------------------
1 | import { faLink, faLinkSlash } from "@fortawesome/free-solid-svg-icons";
2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3 |
4 | import { DataVal, Func, Region } from "@atlasacademy/api-connector";
5 |
6 | import { FuncDescriptorSections } from "./FuncDescriptorSections";
7 |
8 | export default function handleLinkageSection(
9 | region: Region,
10 | sections: FuncDescriptorSections,
11 | func: Func.BasicFunc,
12 | dataVal: DataVal.DataVal
13 | ): void {
14 | const section = sections.linkage,
15 | parts = section.parts;
16 |
17 | if (dataVal.CheckDuplicate === 1) {
18 | parts.push("[This function instance can only be executed once]");
19 | }
20 |
21 | if (dataVal.AddLinkageTargetIndividualty !== undefined && dataVal.BehaveAsFamilyBuff === 1) {
22 | parts.push(
23 | <>
24 | [
25 | {dataVal.UnSubStateWhileLinkedToOthers === 1 ? (
26 |
27 | ) : null}
28 | {dataVal.AddLinkageTargetIndividualty}]
29 | >
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/battle/src/Skill/BattleSkillPassive.ts:
--------------------------------------------------------------------------------
1 | import BattleSkill, { BattleSkillProps, BattleSkillState } from "./BattleSkill";
2 | import BattleSkillFunc from "./BattleSkillFunc";
3 |
4 | export default class BattleSkillPassive extends BattleSkill {
5 | constructor(
6 | public props: BattleSkillProps,
7 | state: BattleSkillState | null,
8 | ) {
9 | super(
10 | props,
11 | state ?? {
12 | cooldown: 0,
13 | funcs: props.skill.functions.map((func, i) => {
14 | return new BattleSkillFunc(
15 | {
16 | actorId: props.actorId,
17 | func,
18 | level: props.level,
19 | passive: true,
20 | },
21 | null,
22 | this,
23 | );
24 | }),
25 | },
26 | );
27 |
28 | this.state.funcs.forEach((func) => (func.parent = this));
29 | }
30 |
31 | clone(): BattleSkillPassive {
32 | return new BattleSkillPassive(this.props, {
33 | ...this.state,
34 | funcs: this.state.funcs.map((func) => func.clone(this)),
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/db/src/Page/Changelog/Settings.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonGroup } from "react-bootstrap";
2 | import { useTranslation } from "react-i18next";
3 |
4 | interface IProps {
5 | visibleOnly: boolean;
6 | updateVisibleOnly: (value: boolean) => void;
7 |
8 | localTime: boolean;
9 | updateLocalTime: (value: boolean) => void;
10 | }
11 |
12 | let Settings = ({ visibleOnly, updateVisibleOnly, localTime, updateLocalTime }: IProps) => {
13 | const { t } = useTranslation();
14 | return (
15 |
16 |
17 |
20 |
23 |
26 |
27 |
28 |
29 |
30 | );
31 | };
32 |
33 | export default Settings;
34 |
--------------------------------------------------------------------------------
/packages/api-connector/src/Schema/WarBoard.ts:
--------------------------------------------------------------------------------
1 | import { Gift } from "./Gift";
2 |
3 | export enum WarBoardStageSquareType {
4 | NORMAL = "normal",
5 | ITEM = "item",
6 | EFFECT = "effect",
7 | TREASURE = "treasure",
8 | WALL = "wall",
9 | }
10 |
11 | export enum WarBoardTreasureRarity {
12 | COMMON = "common",
13 | RARE = "rare",
14 | SRARE = "srare",
15 | COMMON_PLUS = "commonPlus",
16 | RARE_PLUS = "rarePlus",
17 | SRARE_PLUS = "srarePlus",
18 | COMMON_PLUS2 = "commonPlus2",
19 | RARE_PLUS2 = "rarePlus2",
20 | SRARE_PLUS2 = "srarePlus2",
21 | ITEM_ICON = "itemIcon",
22 | ITEM_ICON_PLUS = "itemIconPlus",
23 | ITEM_ICON_PLUS2 = "itemIconPlus2",
24 | }
25 | interface WarBoardTreasure {
26 | warBoardTreasureId: number;
27 | rarity: WarBoardTreasureRarity;
28 | gifts: Gift[];
29 | }
30 | interface WarBoardStageSquare {
31 | squareIndex: number;
32 | type: WarBoardStageSquareType;
33 | effectId: number;
34 | treasures: WarBoardTreasure[];
35 | }
36 | interface WarBoardStage {
37 | warBoardStageId: number;
38 | boardMessage: string;
39 | formationCost: number;
40 | questId: number;
41 | questPhase: number;
42 | squares: WarBoardStageSquare[];
43 | }
44 | export interface WarBoard {
45 | warBoardId: number;
46 | stages: WarBoardStage[];
47 | }
48 |
--------------------------------------------------------------------------------
/packages/db/src/Page/ListingPage.css:
--------------------------------------------------------------------------------
1 | .listing-page > hr {
2 | margin-top: 0;
3 | }
4 |
5 | .listing-page .page-navigator {
6 | float: right;
7 | }
8 |
9 | .listing-page .col-center,
10 | table.listing-table .col-center,
11 | .listing-page .rarity-col,
12 | table.listing-table .rarity-col {
13 | text-align: center;
14 | width: 1px;
15 | }
16 |
17 | @media (min-width: 768px) {
18 | .listing-page .rarity-col,
19 | table.listing-table .rarity-col {
20 | min-width: 10em;
21 | white-space: nowrap;
22 | }
23 | }
24 |
25 | .listing-page .listing-svtId {
26 | font-family: monospace;
27 | font-size: 0.9rem;
28 | }
29 |
30 | .listing-page table th,
31 | .listing-page table td,
32 | table.listing-table th,
33 | table.listing-table td {
34 | vertical-align: middle;
35 | }
36 |
37 | .listing-page #item-type {
38 | justify-content: left;
39 | margin-bottom: 1rem;
40 | }
41 |
42 | .listing-page > .row .btn-group {
43 | width: 100%;
44 | }
45 |
46 | .listing-page #item-search {
47 | margin-left: auto;
48 | margin-bottom: 1rem;
49 | }
50 |
51 | .listing-page #item-search form {
52 | width: 100%;
53 | }
54 |
55 | .listing-page #item-search form input {
56 | margin-left: auto;
57 | width: 100%;
58 | text-align: center;
59 | }
60 |
61 | .listing-page #item-rarity {
62 | margin-bottom: 1rem;
63 | }
64 |
--------------------------------------------------------------------------------
/packages/db/src/Page/MysticCode/MysticCodePortrait.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { MysticCode } from "@atlasacademy/api-connector";
4 |
5 | import "./MysticCodePortrait.css";
6 |
7 | interface IProps {
8 | mysticCode: MysticCode.MysticCode;
9 | }
10 |
11 | class MysticCodePortrait extends React.Component {
12 | render() {
13 | return (
14 |
33 | );
34 | }
35 | }
36 |
37 | export default MysticCodePortrait;
38 |
--------------------------------------------------------------------------------
/packages/paper-moon/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Container } from "react-bootstrap";
3 | import { ConnectedProps, connect } from "react-redux";
4 |
5 | import { battleSetupInitThunk } from "./app/battleSetup/thunks";
6 | import BattleDisplay from "./components/BattleDisplay";
7 | import BattleSetup from "./components/BattleSetup/BattleSetup";
8 | import EnemyActorConfigModal from "./components/EnemyActorConfig/EnemyActorConfigModal";
9 | import Navigation from "./components/Navigation";
10 | import PlayerActorConfigModal from "./components/PlayerActorConfig/PlayerActorConfigModal";
11 |
12 | const mapDispatchToProps = {
13 | init: battleSetupInitThunk,
14 | },
15 | connector = connect(null, mapDispatchToProps);
16 |
17 | type AppProps = ConnectedProps;
18 |
19 | class App extends React.Component {
20 | async componentDidMount() {
21 | await this.props.init();
22 | }
23 |
24 | render() {
25 | return (
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | );
36 | }
37 | }
38 |
39 | export default connector(App);
40 |
--------------------------------------------------------------------------------
/packages/battle/tests/Action/inspectAvailableTest.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 |
3 | import { BattleTeam } from "../../src";
4 | import { BattleCommandAction } from "../../src/Action/BattleCommandAction";
5 | import inspectAvailable from "../../src/Action/inspectAvailable";
6 | import BattleSkill from "../../src/Skill/BattleSkill";
7 | import { createBattle, servant } from "../helpers";
8 |
9 | describe("inspectAvailable", () => {
10 | it("returns available skills", async () => {
11 | const battle = createBattle(),
12 | actor = servant(2, BattleTeam.PLAYER),
13 | manaBurst = actor.skill(2);
14 |
15 | battle.addActor(actor);
16 |
17 | let availableActions = inspectAvailable(battle);
18 | expect(availableActions).to.contain(BattleCommandAction.SERVANT_1_SKILL_1);
19 | expect(availableActions).to.contain(BattleCommandAction.SERVANT_1_SKILL_2);
20 | expect(availableActions).to.contain(BattleCommandAction.SERVANT_1_SKILL_3);
21 |
22 | await manaBurst.activate(battle);
23 | availableActions = inspectAvailable(battle);
24 | expect(availableActions).to.contain(BattleCommandAction.SERVANT_1_SKILL_1);
25 | expect(availableActions).to.not.contain(BattleCommandAction.SERVANT_1_SKILL_2);
26 | expect(availableActions).to.contain(BattleCommandAction.SERVANT_1_SKILL_3);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/packages/api-descriptor/src/Func/extractMutatingDataVals.ts:
--------------------------------------------------------------------------------
1 | import { DataVal } from "@atlasacademy/api-connector";
2 |
3 | import getStaticDataValFields from "./extractStaticDataValFields";
4 |
5 | export default function extractMutatingDataVals(dataVals: DataVal.DataVal[]): DataVal.DataVal[] {
6 | const staticFields = getStaticDataValFields(dataVals),
7 | hasDependingVals = dataVals.filter((val) => val.DependFuncVals !== undefined).length > 0,
8 | mutatingDataVals: DataVal.DataVal[] = [];
9 |
10 | dataVals.forEach((dataVal) => {
11 | const fields = Object.keys(dataVal),
12 | mutatingDataVal: DataVal.DataVal = {};
13 |
14 | fields.forEach((field) => {
15 | if (staticFields.indexOf(field as DataVal.DataValField) !== -1) return;
16 |
17 | // @ts-ignore
18 | mutatingDataVal[field] = dataVal[field];
19 | });
20 |
21 | mutatingDataVals.push(mutatingDataVal);
22 | });
23 |
24 | if (hasDependingVals) {
25 | const dependingVals: DataVal.DataVal[] = dataVals.map((val) => val.DependFuncVals ?? {}),
26 | dependingMutatingVals = extractMutatingDataVals(dependingVals);
27 |
28 | dependingMutatingVals.forEach((dependingMutatingVal, i) => {
29 | mutatingDataVals[i].DependFuncVals = dependingMutatingVal;
30 | });
31 | }
32 |
33 | return mutatingDataVals;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/db/src/Descriptor/CommandCodeDescriptor.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 |
3 | import { CommandCode, Region } from "@atlasacademy/api-connector";
4 |
5 | import FaceIcon from "../Component/FaceIcon";
6 | import useApi from "../Hooks/useApi";
7 | import { lang } from "../Setting/Manager";
8 |
9 | import "./Descriptor.css";
10 |
11 | export default function CommandCodeDescriptor(props: {
12 | region: Region;
13 | commandCode: CommandCode.CommandCodeBasic;
14 | iconHeight?: number;
15 | }) {
16 | return (
17 |
18 | {" "}
19 | {" "}
24 |
25 | {props.commandCode.name}
26 |
27 |
28 | );
29 | }
30 |
31 | export function CommandCodeDescriptorId(props: { region: Region; ccId: number; iconHeight?: number }) {
32 | const { data: cc } = useApi("commandCodeBasic", props.ccId);
33 | return cc !== undefined ? (
34 |
35 | ) : null;
36 | }
37 |
--------------------------------------------------------------------------------
/packages/battle/tests/NoblePhantasm/BattleNoblePhantasmTest.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 |
3 | import { Func } from "../../../api-connector";
4 | import { BattleTeam } from "../../src/Enum/BattleTeam";
5 | import BattleDamageEvent from "../../src/Event/BattleDamageEvent";
6 | import { createBattle, servant } from "../helpers";
7 |
8 | describe("BattleNoblePhantasmTest", () => {
9 | it("hits", () => {
10 | const actor = servant(11, BattleTeam.PLAYER),
11 | noblePhantasm = actor.noblePhantasm();
12 |
13 | expect(noblePhantasm.hits()).to.eql([3, 3, 5, 7, 8, 10, 12, 14, 16, 22]);
14 | });
15 |
16 | it("deals damage", async () => {
17 | const actor = servant(2, BattleTeam.PLAYER),
18 | target = servant(17, BattleTeam.ENEMY),
19 | battle = createBattle();
20 |
21 | battle.addActor(actor);
22 | battle.addActor(target);
23 |
24 | const np = actor.noblePhantasm(),
25 | func = np.func(1);
26 |
27 | expect(func).to.not.be.undefined;
28 | expect(func.props.func.funcType).to.equal(Func.FuncType.DAMAGE_NP);
29 |
30 | const events = await func.execute(battle);
31 | expect(events.length).to.equal(1);
32 |
33 | const event = events[0];
34 | expect(event).to.be.instanceof(BattleDamageEvent);
35 | expect(event.reference.damage).to.equal(40475);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/packages/battle/tests/Func/Implementations/adjustNpFuncTest.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 |
3 | import { BattleTeam } from "../../../src";
4 | import BattleSkill from "../../../src/Skill/BattleSkill";
5 | import { createBattle, servant } from "../../helpers";
6 |
7 | describe("adjustNpFunc", () => {
8 | it("artoria skill 3", async () => {
9 | const actor = servant(2, BattleTeam.PLAYER),
10 | battle = createBattle(),
11 | charge = actor.skill(3);
12 |
13 | battle.addActor(actor);
14 |
15 | expect(actor.gaugePercent()).to.equal(0);
16 | await charge.activate(battle);
17 |
18 | expect(actor.gaugePercent()).to.equal(0.3);
19 | });
20 |
21 | it("shiki saber skill 3", async () => {
22 | const shiki = servant(91, BattleTeam.PLAYER),
23 | waver = servant(37, BattleTeam.PLAYER),
24 | battle = createBattle();
25 |
26 | battle.addActor(shiki);
27 | battle.addActor(waver);
28 |
29 | expect(shiki.gaugePercent()).to.equal(0);
30 |
31 | await waver.skill(2)?.activate(battle);
32 | expect(shiki.gaugePercent()).to.equal(0.1);
33 |
34 | await waver.skill(3)?.activate(battle);
35 | expect(shiki.gaugePercent()).to.equal(0.2);
36 |
37 | await shiki.skill(3)?.activate(battle);
38 | expect(shiki.gaugePercent()).to.equal(0.1);
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Atlas Academy DB
2 |
3 | 
4 |
5 | Source code for the Atlas Academy DB at https://apps.atlasacademy.io/db
6 |
7 | You can join our Discod to discuss the development. Feel free to make pull request or open an issue but we are usually more responsive on Discord.
8 |
9 | [](https://atlasacademy.io/discord)
10 |
11 | ## Development workflow
12 |
13 | ```bash
14 | # clone repo
15 | git clone https://github.com/atlasacademy/apps.git aa-apps
16 | cd aa-apps
17 |
18 | # install lerna and prettier. You should use prettier with the given config to format the files.
19 | npm ci
20 |
21 | # setup packages with local npm link
22 | npx lerna bootstrap --ci --force-local
23 |
24 | # run typescript watchers
25 | npm run watch
26 |
27 | # run dev db on another terminal
28 | npm run start:db
29 |
30 | # ... make changes
31 |
32 | # commit changes
33 | npm run format
34 | git add -A && git commit -m "stuff"
35 | ```
36 |
37 | ## Publish workflow
38 |
39 | This is not applicable if you are not part of the npm.js Atlas Academy org. Ping one of the contributors to publish the changes.
40 |
41 | ```bash
42 | # publish changes
43 | lerna publish
44 |
45 | # merge to master
46 | git checkout master && git pull && git merge dev
47 | ```
48 |
--------------------------------------------------------------------------------
/packages/db/src/Component/Scene.css:
--------------------------------------------------------------------------------
1 | .scene-wrapper {
2 | display: block;
3 | overflow: hidden;
4 | position: relative;
5 | }
6 |
7 | .scene-background {
8 | background-repeat: no-repeat;
9 | bottom: 0;
10 | display: block;
11 | left: 0;
12 | position: absolute;
13 | right: 0;
14 | top: 0;
15 | }
16 |
17 | .scene-figure-wrapper {
18 | bottom: 0;
19 | display: block;
20 | position: absolute;
21 | right: 0;
22 | }
23 |
24 | .scene-figure {
25 | background-repeat: no-repeat;
26 | background-size: 100%;
27 | bottom: 0;
28 | display: block;
29 | left: 0;
30 | position: absolute;
31 | right: 0;
32 | top: 0;
33 | }
34 |
35 | .scene-figure-face,
36 | .scene-equip {
37 | background-repeat: no-repeat;
38 | display: block;
39 | position: absolute;
40 | }
41 |
42 | .scene-foreground {
43 | position: absolute;
44 | height: 100%;
45 | width: 100%;
46 | background-size: cover;
47 | }
48 |
49 | /* Types foreground */
50 | .frame {
51 | background-position: 0 -10px;
52 | }
53 |
54 | /* Mobile Fix - Foreground Types */
55 | @media (max-width: 767px) {
56 | .frame {
57 | background-position: 0 -7px;
58 | }
59 | }
60 |
61 | .sepia-bg {
62 | position: absolute;
63 | height: 100%;
64 | width: 100%;
65 | background: radial-gradient(ellipse at center, #c1701f 0%, #512f0d 80%);
66 | opacity: 0.55;
67 | }
68 |
--------------------------------------------------------------------------------
/packages/db/src/Descriptor/ItemSetDescriptor.tsx:
--------------------------------------------------------------------------------
1 | import { Item, Region, Shop } from "@atlasacademy/api-connector";
2 |
3 | import EntityReferenceDescriptor from "../Descriptor/EntityReferenceDescriptor";
4 | import { IconDescriptorMap } from "../Descriptor/ItemDescriptor";
5 |
6 | const ItemSetDescriptor = (props: { region: Region; itemSet: Shop.ItemSet; itemMap: Map }) => {
7 | const region = props.region,
8 | itemSet = props.itemSet;
9 | switch (itemSet.purchaseType) {
10 | case Shop.PurchaseType.ITEM:
11 | return (
12 | <>
13 | ×
14 | {itemSet.setNum}
15 | >
16 | );
17 | case Shop.PurchaseType.SERVANT:
18 | return (
19 | <>
20 | ×{itemSet.setNum}
21 | >
22 | );
23 | // case Shop.PurchaseType.EVENT_SHOP:
24 | // case Shop.PurchaseType.ITEM_AS_PRESENT:
25 | // case Shop.PurchaseType.GIFT:
26 | default:
27 | return (
28 | <>
29 | {itemSet.purchaseType} {itemSet.targetId} {itemSet.setNum}
30 | >
31 | );
32 | }
33 | };
34 |
35 | export default ItemSetDescriptor;
36 |
--------------------------------------------------------------------------------
/.github/workflows/docker-publish.yml:
--------------------------------------------------------------------------------
1 | name: Docker
2 |
3 | on:
4 | # push:
5 | # branches:
6 | # - master
7 | # paths-ignore:
8 | # - 'packages/db-og-worker/**'
9 | workflow_dispatch:
10 |
11 | env:
12 | # TODO: Change variable to your image's name.
13 | IMAGE_NAME: apps
14 |
15 | jobs:
16 | # Push image to GitHub Packages.
17 | # See also https://docs.docker.com/docker-hub/builds/
18 | push:
19 | runs-on: ubuntu-latest
20 |
21 | steps:
22 | - uses: actions/checkout@v2
23 |
24 | - name: Build image
25 | run: docker build . --file Dockerfile --no-cache --tag $IMAGE_NAME
26 |
27 | - name: Log into GitHub Container Registry
28 | # TODO: Create a PAT with `read:packages` and `write:packages` scopes and save it as an Actions secret `CR_PAT`
29 | run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
30 |
31 | - name: Push image to GitHub Container Registry
32 | run: |
33 | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
34 |
35 | # Change all uppercase to lowercase
36 | IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
37 |
38 | # Use Docker `latest` tag convention
39 | VERSION=latest
40 |
41 | echo IMAGE_ID=$IMAGE_ID
42 | echo VERSION=$VERSION
43 |
44 | docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
45 | docker push $IMAGE_ID:$VERSION
46 |
--------------------------------------------------------------------------------
/packages/paper-moon/src/app/battleSetup/slice.ts:
--------------------------------------------------------------------------------
1 | import { PayloadAction, createSlice } from "@reduxjs/toolkit";
2 |
3 | import { BattleTeam } from "@atlasacademy/battle";
4 |
5 | import { BattleSetupOptionList, BattleSetupState } from "./types";
6 |
7 | const initialState: BattleSetupState = {
8 | pending: true,
9 | canAddActor: true,
10 | servantList: [],
11 | craftEssenceList: [],
12 | selectedTeam: BattleTeam.PLAYER,
13 | };
14 |
15 | export const battleSetupSlice = createSlice({
16 | name: "battleSetup",
17 | initialState,
18 | reducers: {
19 | setCanAddActor: (state, action: PayloadAction) => {
20 | state.canAddActor = action.payload;
21 | },
22 | setCraftEssenceList: (state, action: PayloadAction) => {
23 | state.craftEssenceList = action.payload;
24 | },
25 | setPending: (state, action: PayloadAction) => {
26 | state.pending = action.payload;
27 | },
28 | setServantList: (state, action: PayloadAction) => {
29 | state.servantList = action.payload;
30 | },
31 | selectServant: (state, action: PayloadAction) => {
32 | state.selectedServant = action.payload;
33 | },
34 | selectTeam: (state, action: PayloadAction) => {
35 | state.selectedTeam = action.payload;
36 | },
37 | },
38 | });
39 |
--------------------------------------------------------------------------------
/packages/db/src/Descriptor/QuestEnumDescription.tsx:
--------------------------------------------------------------------------------
1 | import { useTranslation } from "react-i18next";
2 |
3 | import { Quest } from "@atlasacademy/api-connector";
4 | import { toTitleCase } from "@atlasacademy/api-descriptor";
5 |
6 | import { t } from "../i18n";
7 |
8 | export const QuestTypeDescriptionMap = new Map([
9 | [Quest.QuestType.MAIN, t("Main")],
10 | [Quest.QuestType.FREE, t("Free")],
11 | [Quest.QuestType.FRIENDSHIP, t("Interlude")],
12 | [Quest.QuestType.EVENT, t("Event")],
13 | [Quest.QuestType.HERO_BALLAD, t("Hero Ballad")],
14 | [Quest.QuestType.WAR_BOARD, t("War Board")],
15 | ]);
16 |
17 | export const QuestTypeDescription = ({ questType }: { questType: Quest.QuestType }) => {
18 | const { t } = useTranslation();
19 |
20 | switch (questType) {
21 | case Quest.QuestType.MAIN:
22 | return <>{t("Main")}>;
23 | case Quest.QuestType.FREE:
24 | return <>{t("Free")}>;
25 | case Quest.QuestType.FRIENDSHIP:
26 | return <>{t("Interlude")}>;
27 | case Quest.QuestType.EVENT:
28 | return <>{t("Event")}>;
29 | case Quest.QuestType.HERO_BALLAD:
30 | return <>{t("Hero Ballad")}>;
31 | case Quest.QuestType.WAR_BOARD:
32 | return <>{t("War Board")}>;
33 | default:
34 | return <>{toTitleCase(questType)}>;
35 | }
36 | };
37 |
38 | export const QuestFlagDescription = new Map([[Quest.QuestFlag.NONE, "None"]]);
39 |
--------------------------------------------------------------------------------
/packages/db/src/Page/Quest/QuestPhaseNavigator.tsx:
--------------------------------------------------------------------------------
1 | import { Pagination } from "react-bootstrap";
2 |
3 | import { Quest, Region } from "@atlasacademy/api-connector";
4 |
5 | const PhaseNavigator = (props: {
6 | region: Region;
7 | quest: Quest.QuestPhase;
8 | currentPhase: number;
9 | setPhase: (phase: number) => void;
10 | }) => {
11 | const currentPhase = props.currentPhase,
12 | phases = props.quest.phases.sort((a, b) => a - b);
13 | return (
14 |
15 | {
18 | props.setPhase(currentPhase - 1);
19 | }}
20 | />
21 | {props.quest.phases.map((phase) => (
22 | {
26 | props.setPhase(phase);
27 | }}
28 | >
29 | {phase}
30 |
31 | ))}
32 | {
35 | props.setPhase(currentPhase + 1);
36 | }}
37 | />
38 |
39 | );
40 | };
41 | export default PhaseNavigator;
42 |
--------------------------------------------------------------------------------
/packages/battle/tests/Skill/BattleSkillTest.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 |
3 | import { BattleTeam } from "../../src";
4 | import BattleSkill from "../../src/Skill/BattleSkill";
5 | import { createBattle, servant } from "../helpers";
6 |
7 | describe("BattleSkill", () => {
8 | it("cooldown", async () => {
9 | const battle = createBattle(),
10 | actor = servant(2, BattleTeam.PLAYER),
11 | charisma = actor.skill(1);
12 |
13 | battle.addActor(actor);
14 |
15 | expect(charisma.level()).to.equal(10);
16 | expect(charisma.available()).to.be.true;
17 | expect(charisma.cooldown()).to.equal(0);
18 |
19 | await charisma.activate(battle);
20 |
21 | expect(charisma.available()).to.be.false;
22 | expect(charisma.cooldown()).to.equal(5);
23 | });
24 |
25 | it("cooldown is level dependant", async () => {
26 | const battle = createBattle(),
27 | actor = servant(2, BattleTeam.PLAYER, {
28 | skillLevels: [1],
29 | }),
30 | charisma = actor.skill(1);
31 |
32 | battle.addActor(actor);
33 |
34 | expect(charisma.level()).to.equal(1);
35 | expect(charisma.available()).to.be.true;
36 | expect(charisma.cooldown()).to.equal(0);
37 |
38 | await charisma.activate(battle);
39 |
40 | expect(charisma.available()).to.be.false;
41 | expect(charisma.cooldown()).to.equal(7);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------