├── public ├── favicon.ico ├── assets │ ├── he.webp │ ├── waw.webp │ ├── 1star.webp │ ├── 2star.webp │ ├── 3star.webp │ ├── aleph.webp │ ├── blunt.webp │ ├── coin.webp │ ├── dodge.webp │ ├── envy.webp │ ├── gloom.webp │ ├── guard.webp │ ├── lust.webp │ ├── pride.webp │ ├── slash.webp │ ├── sloth.webp │ ├── teth.webp │ ├── wrath.webp │ ├── zayin.webp │ ├── counter.webp │ ├── gluttony.webp │ ├── he-label.webp │ ├── pierce.webp │ ├── he-bright.webp │ ├── teth-label.webp │ ├── waw-bright.webp │ ├── waw-label.webp │ ├── aleph-bright.webp │ ├── aleph-label.webp │ ├── teth-bright.webp │ ├── zayin-bright.webp │ ├── zayin-label.webp │ ├── hex-gloom.svg │ ├── hex-lust.svg │ ├── hex-none.svg │ ├── hex-pride.svg │ ├── hex-sloth.svg │ ├── hex-wrath.svg │ ├── hex-envy.svg │ └── hex-gluttony.svg ├── icons │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-256x256.png │ ├── browserconfig.xml │ └── safari-pinned-tab.svg ├── sinners │ ├── faust │ │ ├── ego │ │ │ ├── 9 2.webp │ │ │ ├── fluid sac.webp │ │ │ ├── hex nail.webp │ │ │ ├── telepole.webp │ │ │ └── representation emitter.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── the one who grips.webp │ │ │ ├── blade lineage salsu.webp │ │ │ ├── lobotomy ego regret.webp │ │ │ ├── lobotomy corp. remnant.webp │ │ │ ├── seven south section 4.webp │ │ │ ├── w corp. l2 cleanup agent.webp │ │ │ └── zwei association south section 4.webp │ ├── gregor │ │ ├── ego │ │ │ ├── aedd.webp │ │ │ ├── lantern.webp │ │ │ ├── legerdemain.webp │ │ │ ├── garden of thorns.webp │ │ │ └── suddenly, one day.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── liu section 6.webp │ │ │ ├── rb sous chef.webp │ │ │ ├── kurokumo clan captain.webp │ │ │ ├── g corp. manager corporal.webp │ │ │ ├── rosespanner workshop fixer.webp │ │ │ ├── twinhook pirates first mate.webp │ │ │ └── zwei association south section 4.webp │ ├── hong lu │ │ ├── ego │ │ │ ├── soda.webp │ │ │ ├── roseate desire.webp │ │ │ ├── land of illusion.webp │ │ │ ├── dimension shredder.webp │ │ │ └── effervescent corrosion.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── liu section 5.webp │ │ │ ├── hook office fixer.webp │ │ │ ├── kurokumo wakashu.webp │ │ │ ├── tingtang gangleader.webp │ │ │ ├── dieci south section 4.webp │ │ │ ├── w corp. l2 cleanup agent.webp │ │ │ └── k corp. class 3 excision staff.webp │ ├── outis │ │ ├── ego │ │ │ ├── holiday.webp │ │ │ ├── sunshower.webp │ │ │ ├── ebony stem.webp │ │ │ ├── to páthos máthos.webp │ │ │ └── ya śūnyatā tad rūpam.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── cinq south section 4.webp │ │ │ ├── g corp. head manager.webp │ │ │ ├── molar office fixer.webp │ │ │ ├── blade lineage cutthroat.webp │ │ │ ├── lobotomy ego magic bullet.webp │ │ │ └── seven section 6 director.webp │ ├── ryoshu │ │ ├── ego │ │ │ ├── soda.webp │ │ │ ├── red eyes.webp │ │ │ ├── 4th match flame.webp │ │ │ ├── blind obsession.webp │ │ │ ├── red eyes (open).webp │ │ │ └── forest for the flames.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── chef de cuisine.webp │ │ │ ├── kurokumo wakashu.webp │ │ │ ├── seven section 6.webp │ │ │ ├── lccb assistant manager.webp │ │ │ ├── w corp. l3 cleanup agent.webp │ │ │ └── liu assoc. south section 4.webp │ ├── sinclair │ │ ├── ego │ │ │ ├── 9 2.webp │ │ │ ├── lantern.webp │ │ │ ├── impending day.webp │ │ │ ├── lifetime stew.webp │ │ │ └── branch of knowledge.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── zwei section 6.webp │ │ │ ├── blade lineage salsu.webp │ │ │ ├── jefe de los mariachis.webp │ │ │ ├── lobotomy ego red sheet.webp │ │ │ ├── molar boatworks fixer.webp │ │ │ ├── the one who shall grip.webp │ │ │ └── cinq south section 4 director.webp │ ├── heathcliff │ │ ├── ego │ │ │ ├── aedd.webp │ │ │ ├── holiday.webp │ │ │ ├── bodysack.webp │ │ │ ├── telepole.webp │ │ │ └── ya śūnyatā tad rūpam.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── shi section 5.webp │ │ │ ├── n corp. kleinhammer.webp │ │ │ ├── lobotomy ego sunshower.webp │ │ │ ├── seven south section 4.webp │ │ │ ├── the pequod harpooneer.webp │ │ │ ├── r corp. 4th pack rabbit.webp │ │ │ └── oufi assoc. south section 3.webp │ ├── ishmael │ │ ├── ego │ │ │ ├── capote.webp │ │ │ ├── snagharpoon.webp │ │ │ ├── blind obsession.webp │ │ │ ├── roseate desire.webp │ │ │ └── ardor blossom star.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── shi section 5.webp │ │ │ ├── the pequod captain.webp │ │ │ ├── lccb assistant manager.webp │ │ │ ├── lobotomy ego sloshing.webp │ │ │ ├── molar boatworks fixer.webp │ │ │ ├── r corp. 4th pack reindeer.webp │ │ │ └── liu association south section 4.webp │ ├── meursault │ │ ├── ego │ │ │ ├── capote.webp │ │ │ ├── regret.webp │ │ │ ├── pursuance.webp │ │ │ ├── chains of others.webp │ │ │ └── you want to get beat hurtily.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── liu section 6.webp │ │ │ ├── blade lineage mentor.webp │ │ │ ├── n corp. grosshammer.webp │ │ │ ├── r corp. 4th pack rhino.webp │ │ │ ├── rosespanner workshop fixer.webp │ │ │ ├── the middle little brother.webp │ │ │ └── w corp. l2 cleanup agent.webp │ ├── rodion │ │ ├── ego │ │ │ ├── pursuance.webp │ │ │ ├── rime shank.webp │ │ │ ├── what is cast.webp │ │ │ ├── 4th match flame.webp │ │ │ └── effervescent corrosion.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── kurokumo henchwoman.webp │ │ │ ├── dieci south section 4.webp │ │ │ ├── n corp. mittelhammer.webp │ │ │ ├── lccb assistant manager.webp │ │ │ ├── rosespanner workshop rep..webp │ │ │ ├── Zwei Association South Section 5.webp │ │ │ └── liu assoc. south section 4 director.webp │ ├── yi sang │ │ ├── ego │ │ │ ├── sunshower.webp │ │ │ ├── 4th match flame.webp │ │ │ ├── crow_s eye view.webp │ │ │ ├── wishing cairn.webp │ │ │ └── dimension shredder.webp │ │ └── identities │ │ │ ├── lcb sinner.webp │ │ │ ├── seven section 6.webp │ │ │ ├── molar office fixer.webp │ │ │ ├── blade lineage salsu.webp │ │ │ ├── dieci south section 4.webp │ │ │ ├── the pequod first mate.webp │ │ │ ├── effloresced ego spicebush.webp │ │ │ └── w corp. l3 cleanup agent.webp │ └── don quixote │ │ ├── ego │ │ ├── telepole.webp │ │ ├── fluid sac.webp │ │ ├── lifetime stew.webp │ │ ├── wishing cairn.webp │ │ └── la sangre de sancho.webp │ │ └── identities │ │ ├── lcb sinner.webp │ │ ├── shi section 5.webp │ │ ├── blade lineage salsu.webp │ │ ├── lobotomy ego lantern.webp │ │ ├── n corp. mittelhammer.webp │ │ ├── the middle little sister.webp │ │ ├── w corp. l3 cleanup agent.webp │ │ └── cinq south section 5 director.webp ├── site.webmanifest └── egos.json ├── next.config.js ├── components ├── Footer.module.scss ├── TeamBoard.module.scss ├── SkillHexagon.module.scss ├── Button.tsx ├── Modal.module.scss ├── Button.module.scss ├── SkillHexagon.tsx ├── Footer.tsx ├── AffinitySummary.module.scss ├── EgoComponent.module.scss ├── TeamBoard.tsx ├── EgoCostSummary.module.scss ├── EgoCostSummary.tsx ├── EgoComponent.tsx ├── Modal.tsx ├── EgoSelection.tsx ├── IdentitySelection.tsx ├── AffinitySummary.tsx ├── SinnerCard.module.scss ├── IdentitySelection.module.scss ├── EgoSelection.module.scss └── SinnerCard.tsx ├── helpers ├── assets.module.scss ├── costCalcs.ts ├── loadJson.ts ├── assets.ts └── sinnerData.ts ├── README.md ├── styles ├── index.module.scss ├── _vars.scss ├── globals.scss └── _mixins.scss ├── package.json ├── .gitignore ├── tsconfig.json ├── pages ├── _app.tsx └── index.tsx ├── types └── data.ts ├── .github └── workflows │ └── nextjs.yml ├── hooks ├── teamContext.tsx └── initialTeam.json └── LICENSE /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/assets/he.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/he.webp -------------------------------------------------------------------------------- /public/assets/waw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/waw.webp -------------------------------------------------------------------------------- /public/assets/1star.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/1star.webp -------------------------------------------------------------------------------- /public/assets/2star.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/2star.webp -------------------------------------------------------------------------------- /public/assets/3star.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/3star.webp -------------------------------------------------------------------------------- /public/assets/aleph.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/aleph.webp -------------------------------------------------------------------------------- /public/assets/blunt.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/blunt.webp -------------------------------------------------------------------------------- /public/assets/coin.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/coin.webp -------------------------------------------------------------------------------- /public/assets/dodge.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/dodge.webp -------------------------------------------------------------------------------- /public/assets/envy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/envy.webp -------------------------------------------------------------------------------- /public/assets/gloom.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/gloom.webp -------------------------------------------------------------------------------- /public/assets/guard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/guard.webp -------------------------------------------------------------------------------- /public/assets/lust.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/lust.webp -------------------------------------------------------------------------------- /public/assets/pride.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/pride.webp -------------------------------------------------------------------------------- /public/assets/slash.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/slash.webp -------------------------------------------------------------------------------- /public/assets/sloth.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/sloth.webp -------------------------------------------------------------------------------- /public/assets/teth.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/teth.webp -------------------------------------------------------------------------------- /public/assets/wrath.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/wrath.webp -------------------------------------------------------------------------------- /public/assets/zayin.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/zayin.webp -------------------------------------------------------------------------------- /public/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/favicon.ico -------------------------------------------------------------------------------- /public/assets/counter.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/counter.webp -------------------------------------------------------------------------------- /public/assets/gluttony.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/gluttony.webp -------------------------------------------------------------------------------- /public/assets/he-label.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/he-label.webp -------------------------------------------------------------------------------- /public/assets/pierce.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/pierce.webp -------------------------------------------------------------------------------- /public/assets/he-bright.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/he-bright.webp -------------------------------------------------------------------------------- /public/assets/teth-label.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/teth-label.webp -------------------------------------------------------------------------------- /public/assets/waw-bright.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/waw-bright.webp -------------------------------------------------------------------------------- /public/assets/waw-label.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/waw-label.webp -------------------------------------------------------------------------------- /public/assets/aleph-bright.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/aleph-bright.webp -------------------------------------------------------------------------------- /public/assets/aleph-label.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/aleph-label.webp -------------------------------------------------------------------------------- /public/assets/teth-bright.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/teth-bright.webp -------------------------------------------------------------------------------- /public/assets/zayin-bright.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/zayin-bright.webp -------------------------------------------------------------------------------- /public/assets/zayin-label.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/assets/zayin-label.webp -------------------------------------------------------------------------------- /public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/mstile-150x150.png -------------------------------------------------------------------------------- /public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/sinners/faust/ego/9 2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/ego/9 2.webp -------------------------------------------------------------------------------- /public/sinners/gregor/ego/aedd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/ego/aedd.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/ego/soda.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/ego/soda.webp -------------------------------------------------------------------------------- /public/sinners/outis/ego/holiday.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/ego/holiday.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/ego/soda.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/ego/soda.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/ego/9 2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/ego/9 2.webp -------------------------------------------------------------------------------- /public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/icons/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/icons/android-chrome-256x256.png -------------------------------------------------------------------------------- /public/sinners/faust/ego/fluid sac.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/ego/fluid sac.webp -------------------------------------------------------------------------------- /public/sinners/faust/ego/hex nail.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/ego/hex nail.webp -------------------------------------------------------------------------------- /public/sinners/faust/ego/telepole.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/ego/telepole.webp -------------------------------------------------------------------------------- /public/sinners/gregor/ego/lantern.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/ego/lantern.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/ego/aedd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/ego/aedd.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/ego/capote.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/ego/capote.webp -------------------------------------------------------------------------------- /public/sinners/outis/ego/sunshower.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/ego/sunshower.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/ego/red eyes.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/ego/red eyes.webp -------------------------------------------------------------------------------- /public/sinners/gregor/ego/legerdemain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/ego/legerdemain.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/ego/holiday.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/ego/holiday.webp -------------------------------------------------------------------------------- /public/sinners/meursault/ego/capote.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/ego/capote.webp -------------------------------------------------------------------------------- /public/sinners/meursault/ego/regret.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/ego/regret.webp -------------------------------------------------------------------------------- /public/sinners/outis/ego/ebony stem.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/ego/ebony stem.webp -------------------------------------------------------------------------------- /public/sinners/rodion/ego/pursuance.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/ego/pursuance.webp -------------------------------------------------------------------------------- /public/sinners/rodion/ego/rime shank.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/ego/rime shank.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/ego/lantern.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/ego/lantern.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/ego/sunshower.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/ego/sunshower.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/ego/telepole.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/ego/telepole.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/ego/bodysack.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/ego/bodysack.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/ego/telepole.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/ego/telepole.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/ego/snagharpoon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/ego/snagharpoon.webp -------------------------------------------------------------------------------- /public/sinners/meursault/ego/pursuance.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/ego/pursuance.webp -------------------------------------------------------------------------------- /public/sinners/rodion/ego/what is cast.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/ego/what is cast.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/ego/fluid sac.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/ego/fluid sac.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/gregor/ego/garden of thorns.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/ego/garden of thorns.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/ego/roseate desire.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/ego/roseate desire.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/ego/blind obsession.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/ego/blind obsession.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/ego/roseate desire.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/ego/roseate desire.webp -------------------------------------------------------------------------------- /public/sinners/outis/ego/to páthos máthos.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/ego/to páthos máthos.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/rodion/ego/4th match flame.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/ego/4th match flame.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/ego/4th match flame.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/ego/4th match flame.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/ego/blind obsession.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/ego/blind obsession.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/ego/red eyes (open).webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/ego/red eyes (open).webp -------------------------------------------------------------------------------- /public/sinners/sinclair/ego/impending day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/ego/impending day.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/ego/lifetime stew.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/ego/lifetime stew.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/ego/4th match flame.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/ego/4th match flame.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/ego/crow_s eye view.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/ego/crow_s eye view.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/ego/wishing cairn.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/ego/wishing cairn.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/ego/lifetime stew.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/ego/lifetime stew.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/ego/wishing cairn.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/ego/wishing cairn.webp -------------------------------------------------------------------------------- /public/sinners/gregor/ego/suddenly, one day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/ego/suddenly, one day.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/ego/land of illusion.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/ego/land of illusion.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/faust/ego/representation emitter.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/ego/representation emitter.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/liu section 6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/liu section 6.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/rb sous chef.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/rb sous chef.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/ego/dimension shredder.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/ego/dimension shredder.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/liu section 5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/liu section 5.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/ego/ardor blossom star.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/ego/ardor blossom star.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/shi section 5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/shi section 5.webp -------------------------------------------------------------------------------- /public/sinners/meursault/ego/chains of others.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/ego/chains of others.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/outis/ego/ya śūnyatā tad rūpam.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/ego/ya śūnyatā tad rūpam.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/ego/forest for the flames.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/ego/forest for the flames.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/ego/branch of knowledge.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/ego/branch of knowledge.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/ego/dimension shredder.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/ego/dimension shredder.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/lcb sinner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/lcb sinner.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/the one who grips.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/the one who grips.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/ego/effervescent corrosion.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/ego/effervescent corrosion.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/liu section 6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/liu section 6.webp -------------------------------------------------------------------------------- /public/sinners/rodion/ego/effervescent corrosion.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/ego/effervescent corrosion.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/chef de cuisine.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/chef de cuisine.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/kurokumo wakashu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/kurokumo wakashu.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/seven section 6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/seven section 6.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/zwei section 6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/zwei section 6.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/seven section 6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/seven section 6.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/ego/la sangre de sancho.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/ego/la sangre de sancho.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/shi section 5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/shi section 5.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/blade lineage salsu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/blade lineage salsu.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/lobotomy ego regret.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/lobotomy ego regret.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/ego/ya śūnyatā tad rūpam.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/ego/ya śūnyatā tad rūpam.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/shi section 5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/shi section 5.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/hook office fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/hook office fixer.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/kurokumo wakashu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/kurokumo wakashu.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/the pequod captain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/the pequod captain.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/cinq south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/cinq south section 4.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/g corp. head manager.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/g corp. head manager.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/molar office fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/molar office fixer.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/kurokumo henchwoman.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/kurokumo henchwoman.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/molar office fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/molar office fixer.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/lobotomy corp. remnant.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/lobotomy corp. remnant.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/seven south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/seven south section 4.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/kurokumo clan captain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/kurokumo clan captain.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/tingtang gangleader.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/tingtang gangleader.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/dieci south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/dieci south section 4.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/n corp. mittelhammer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/n corp. mittelhammer.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/blade lineage salsu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/blade lineage salsu.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/blade lineage salsu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/blade lineage salsu.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/blade lineage salsu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/blade lineage salsu.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/w corp. l2 cleanup agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/w corp. l2 cleanup agent.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/g corp. manager corporal.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/g corp. manager corporal.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/n corp. kleinhammer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/n corp. kleinhammer.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/dieci south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/dieci south section 4.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/lccb assistant manager.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/lccb assistant manager.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/lobotomy ego sloshing.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/lobotomy ego sloshing.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/molar boatworks fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/molar boatworks fixer.webp -------------------------------------------------------------------------------- /public/sinners/meursault/ego/you want to get beat hurtily.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/ego/you want to get beat hurtily.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/blade lineage mentor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/blade lineage mentor.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/n corp. grosshammer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/n corp. grosshammer.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/blade lineage cutthroat.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/blade lineage cutthroat.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/lobotomy ego magic bullet.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/lobotomy ego magic bullet.webp -------------------------------------------------------------------------------- /public/sinners/outis/identities/seven section 6 director.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/outis/identities/seven section 6 director.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/lccb assistant manager.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/lccb assistant manager.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/lccb assistant manager.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/lccb assistant manager.webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/w corp. l3 cleanup agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/w corp. l3 cleanup agent.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/jefe de los mariachis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/jefe de los mariachis.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/lobotomy ego red sheet.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/lobotomy ego red sheet.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/molar boatworks fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/molar boatworks fixer.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/the one who shall grip.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/the one who shall grip.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/dieci south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/dieci south section 4.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/the pequod first mate.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/the pequod first mate.webp -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | sassOptions: { 5 | includePaths: [path.join(__dirname, 'styles'), 'node_modules'], 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/lobotomy ego lantern.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/lobotomy ego lantern.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/n corp. mittelhammer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/n corp. mittelhammer.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/rosespanner workshop fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/rosespanner workshop fixer.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/lobotomy ego sunshower.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/lobotomy ego sunshower.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/seven south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/seven south section 4.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/the pequod harpooneer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/the pequod harpooneer.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/w corp. l2 cleanup agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/w corp. l2 cleanup agent.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/r corp. 4th pack reindeer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/r corp. 4th pack reindeer.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/r corp. 4th pack rhino.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/r corp. 4th pack rhino.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/rosespanner workshop rep..webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/rosespanner workshop rep..webp -------------------------------------------------------------------------------- /public/sinners/ryoshu/identities/liu assoc. south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ryoshu/identities/liu assoc. south section 4.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/effloresced ego spicebush.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/effloresced ego spicebush.webp -------------------------------------------------------------------------------- /public/sinners/yi sang/identities/w corp. l3 cleanup agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/yi sang/identities/w corp. l3 cleanup agent.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/the middle little sister.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/the middle little sister.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/w corp. l3 cleanup agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/w corp. l3 cleanup agent.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/twinhook pirates first mate.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/twinhook pirates first mate.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/r corp. 4th pack rabbit.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/r corp. 4th pack rabbit.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/rosespanner workshop fixer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/rosespanner workshop fixer.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/the middle little brother.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/the middle little brother.webp -------------------------------------------------------------------------------- /public/sinners/meursault/identities/w corp. l2 cleanup agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/meursault/identities/w corp. l2 cleanup agent.webp -------------------------------------------------------------------------------- /public/sinners/faust/identities/zwei association south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/faust/identities/zwei association south section 4.webp -------------------------------------------------------------------------------- /public/sinners/heathcliff/identities/oufi assoc. south section 3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/heathcliff/identities/oufi assoc. south section 3.webp -------------------------------------------------------------------------------- /public/sinners/hong lu/identities/k corp. class 3 excision staff.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/hong lu/identities/k corp. class 3 excision staff.webp -------------------------------------------------------------------------------- /public/sinners/sinclair/identities/cinq south section 4 director.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/sinclair/identities/cinq south section 4 director.webp -------------------------------------------------------------------------------- /public/sinners/don quixote/identities/cinq south section 5 director.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/don quixote/identities/cinq south section 5 director.webp -------------------------------------------------------------------------------- /public/sinners/gregor/identities/zwei association south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/gregor/identities/zwei association south section 4.webp -------------------------------------------------------------------------------- /public/sinners/ishmael/identities/liu association south section 4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/ishmael/identities/liu association south section 4.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/Zwei Association South Section 5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/Zwei Association South Section 5.webp -------------------------------------------------------------------------------- /public/sinners/rodion/identities/liu assoc. south section 4 director.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darylhcw/lc-teambuilder/HEAD/public/sinners/rodion/identities/liu assoc. south section 4 director.webp -------------------------------------------------------------------------------- /components/Footer.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | .footer { 4 | text-align: center; 5 | 6 | p { 7 | margin: 0.4rem 8 | } 9 | 10 | @media (max-width: vars.$mobile-screen) { 11 | font-size: 12px; 12 | } 13 | } -------------------------------------------------------------------------------- /helpers/assets.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | :export { 4 | wrath: vars.$wrath; 5 | lust: vars.$lust; 6 | sloth: vars.$sloth; 7 | gluttony: vars.$gluttony; 8 | gloom: vars.$gloom; 9 | pride: vars.$pride; 10 | envy: vars.$envy; 11 | } -------------------------------------------------------------------------------- /public/assets/hex-gloom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-lust.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-none.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-pride.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-sloth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-wrath.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-envy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/hex-gluttony.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lc-teambuilder 2 | Teambuilder for [Limbus Company](https://limbuscompany.com/). Static site made with NextJS written in TypeScript for practice. 3 | 4 | https://darylhcw.github.io/lc-teambuilder/ 5 | 6 | 7 | 8 | ___ 9 | 10 | To run, make sure you have [pnpm](https://pnpm.io/) installed, then simply do: 11 | 12 | - pnpm install 13 | - pnpm run dev 14 | -------------------------------------------------------------------------------- /components/TeamBoard.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | $sinner-card-gap: 8px; 4 | 5 | .sinner-board { 6 | display: grid; 7 | grid-template-columns: 8 | repeat(auto-fit, 9 | minmax( 10 | max(vars.$sinner-card-width, (100% - 5*$sinner-card-gap)/6), 11 | 1fr 12 | ) 13 | ); 14 | grid-gap: $sinner-card-gap; 15 | 16 | padding: 10px; 17 | } 18 | -------------------------------------------------------------------------------- /components/SkillHexagon.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | 4 | .container { 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | 9 | position: relative; // ref for absolutely positoned images. 10 | height: 100%; 11 | aspect-ratio: 1; 12 | } 13 | 14 | .hexagon { 15 | height: 100%; 16 | } 17 | 18 | .skill { 19 | position: absolute; 20 | height: 75%; 21 | 22 | z-index: 1; 23 | } 24 | -------------------------------------------------------------------------------- /styles/index.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | $board-max-width: 1720px; 4 | 5 | .main { 6 | margin: 16px 40px; 7 | max-width: $board-max-width; 8 | @media (min-width: ($board-max-width)) { 9 | margin: 16px auto; 10 | } 11 | @media (max-width: vars.$small-screen) { 12 | margin: 0 12px; 13 | } 14 | 15 | footer { 16 | margin-top: 5rem; 17 | } 18 | } 19 | 20 | .board-buttons-container { 21 | display: flex; 22 | justify-content: flex-end; 23 | margin: 1rem 0 5rem; 24 | } -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LC TeamBuilder", 3 | "short_name": "LC TeamBuilder", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "android-chrome-256x256.png", 12 | "sizes": "256x256", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "next dev", 5 | "build": "next build", 6 | "start": "next start" 7 | }, 8 | "dependencies": { 9 | "dotenv": "^16.0.3", 10 | "next": "^13.2.4", 11 | "next-pwa": "^5.6.0", 12 | "normalize.css": "^8.0.1", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "17.0.4", 18 | "@types/react": "17.0.38", 19 | "@types/react-dom": "^18.0.11", 20 | "sass": "^1.60.0", 21 | "typescript": "4.5.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /components/Button.tsx: -------------------------------------------------------------------------------- 1 | import styles from './Button.module.scss'; 2 | 3 | export interface ButtonProps { 4 | disabled?: boolean; 5 | onClick?: (event: React.MouseEvent) => void; 6 | children?: React.ReactNode; 7 | }; 8 | 9 | export default function Button({ 10 | disabled = false, 11 | onClick, 12 | children 13 | } : ButtonProps 14 | ){ 15 | return ( 16 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /components/Modal.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | .overlay { 4 | position: fixed; 5 | top: 0; 6 | left: 0; 7 | right: 0; 8 | bottom: 0; 9 | 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | 14 | background: rgba(0, 0, 0, .8); 15 | z-index: 99; 16 | } 17 | 18 | .container { 19 | min-width: min(80%, calc(vars.$large-screen*0.8)); 20 | max-width: vars.$large-screen; 21 | 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | 26 | margin: 0 vars.pxToRem(80px); 27 | @media (max-width: vars.$small-screen) { 28 | margin: 0 vars.pxToRem(24px); 29 | } 30 | } -------------------------------------------------------------------------------- /components/Button.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | @use 'mixins'; 3 | 4 | 5 | .button { 6 | @include mixins.hover-focus-highlight; 7 | 8 | position: relative; // for overlay. 9 | 10 | height: vars.$button-h; 11 | padding: 0.3rem 1rem; 12 | 13 | color: vars.$text-brown; 14 | font-size: vars.pxToRem(20px); 15 | font-weight: bold; 16 | 17 | background: vars.$page-bg; 18 | border-radius: 15px; 19 | border: 2px solid vars.$board-light; 20 | 21 | &:disabled { 22 | opacity: 0.5; 23 | } 24 | 25 | @media (max-width: vars.$mobile-screen) { 26 | height: vars.$button-h-mobile; 27 | padding: 0.3rem 0.7rem; 28 | font-size: vars.pxToRem(16px); 29 | } 30 | } -------------------------------------------------------------------------------- /components/SkillHexagon.tsx: -------------------------------------------------------------------------------- 1 | import { Sin, AttackType, DefenseType } from '@/types/data'; 2 | import { getSkillTypeAsset, getSinTypeHexAsset } from '@/helpers/assets'; 3 | import styles from './SkillHexagon.module.scss'; 4 | 5 | interface SkillHexagonProps { 6 | affinity?: Sin; 7 | type: AttackType | DefenseType; 8 | defense?: boolean; 9 | } 10 | 11 | export default function SkillHexagon({affinity, type, defense=false} : SkillHexagonProps) { 12 | return ( 13 |
14 | {affinity} 17 | {type} 20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./Footer.module.scss"; 2 | 3 | export default function Footer() { 4 | return ( 5 | 26 | ) 27 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # next-pwa 39 | /public/precache.*.*.js 40 | /public/sw.js 41 | /public/workbox-*.js 42 | /public/worker-*.js 43 | /public/fallback-*.js 44 | /public/precache.*.*.js.map 45 | /public/sw.js.map 46 | /public/workbox-*.js.map 47 | /public/worker-*.js.map 48 | /public/fallback-*.js 49 | 50 | # python 51 | */venv 52 | scriptz/ -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | 18 | "baseUrl": ".", 19 | "paths": { 20 | "@/components/*": ["components/*"], 21 | "@/api/*": ["pages/api/*"], 22 | "@/styles/*": ["styles/*"], 23 | "@/types/*": ["types/*"], 24 | "@/hooks/*": ["hooks/*"], 25 | "@/helpers/*": ["helpers/*"], 26 | }, 27 | }, 28 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /styles/_vars.scss: -------------------------------------------------------------------------------- 1 | // This is a partial file for global constants and helpers. 2 | @use 'sass:math'; 3 | 4 | // Color 5 | $page-bg: #171511; 6 | $board-bg: #331E15; 7 | $board-light: #A3703F; 8 | 9 | $grey: #808080; 10 | $blood-red: #880808; 11 | 12 | $wrath: #EE1D1D; 13 | $lust: #BA5320; 14 | $sloth: #CAC202; 15 | $gluttony: #43762F; 16 | $gloom: #0BE4E4; 17 | $pride: #4040E5; 18 | $envy: #D00DD0; 19 | 20 | $text-red: red; 21 | $text-brown: #DDC3A1; 22 | $text-yellow: #FBC500; 23 | $orange-highlight: #FE8C01; 24 | 25 | // Sizes 26 | $sinner-card-width: 200px; 27 | $button-h: 50px; 28 | $button-h-mobile: 36px; 29 | 30 | // Breakpoints 31 | $large-screen: 2560px; 32 | $small-screen: 720px; 33 | $mobile-screen: 450px; 34 | 35 | // Other constants 36 | $before-highlight-border-z: 2; 37 | 38 | // Helpers 39 | @function pxToRem($pxValue) { 40 | @return math.div($pxValue, 16px) * 1rem; 41 | } 42 | 43 | // Aspect ratio to set for elems/imgs within the sinner card. 44 | // To make sure they scale if the card gets wider. 45 | @function getSinnerCardAspectRatio($elemHeight) { 46 | @return math.div($sinner-card-width, $elemHeight); 47 | } 48 | -------------------------------------------------------------------------------- /components/AffinitySummary.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | .summary-board { 4 | display: inline-grid; 5 | grid-template-columns: 1fr 1fr; 6 | grid-template-areas: 7 | "header header" 8 | "sins attacks"; 9 | column-gap: 1rem; 10 | padding: 1rem; 11 | margin-bottom: 2rem; 12 | margin-right: 2rem; 13 | 14 | h2 { 15 | grid-area: header; 16 | margin-bottom: 1rem; 17 | 18 | font-weight: normal; 19 | color: vars.$text-yellow; 20 | font-size: vars.pxToRem(30px); 21 | @media (max-width: vars.$mobile-screen) { 22 | font-size: vars.pxToRem(24px); 23 | } 24 | } 25 | } 26 | 27 | .summary-items-container { 28 | display: flex; 29 | flex-direction: column; 30 | } 31 | .sins-container { 32 | @extend .summary-items-container; 33 | grid-area: sins; 34 | } 35 | .attacks-container { 36 | @extend .summary-items-container; 37 | grid-area: attacks; 38 | } 39 | 40 | .image-cost-pair { 41 | display: flex; 42 | align-items: center; 43 | margin-bottom: 0.5rem; 44 | 45 | span { 46 | font-size: vars.pxToRem(20px); 47 | } 48 | img { 49 | width: 35px; 50 | margin-right: 0.5rem; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /helpers/costCalcs.ts: -------------------------------------------------------------------------------- 1 | import { TeamResources, EgoData, Passive } from '@/types/data'; 2 | 3 | // Obtain TeamResources from consuming the context and pass it here. 4 | function passiveSufficient(resources: TeamResources, passive?: Passive) { 5 | if (!passive) return false; 6 | 7 | const resource = resources.get(passive.affinity); 8 | if (!resource) return false; 9 | 10 | return resource >= passive.cost; 11 | } 12 | 13 | function egoSufficient(resources: TeamResources, ego?: EgoData) { 14 | if (!ego) return false; 15 | 16 | for (const cost of ego.costs) { 17 | const resource = resources.get(cost.affinity); 18 | if (!resource) return false; 19 | 20 | if (resource < cost.cost) return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | function getEgoResourcesMap(egoData: EgoData[]) { 27 | const resources : TeamResources = new Map(); 28 | for (const ego of egoData) { 29 | for (const cost of ego.costs) { 30 | const old = resources.get(cost.affinity) ?? 0; 31 | resources.set(cost.affinity, old + cost.cost); 32 | } 33 | } 34 | 35 | return resources; 36 | } 37 | 38 | 39 | export { 40 | passiveSufficient, egoSufficient, 41 | getEgoResourcesMap, 42 | } -------------------------------------------------------------------------------- /public/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /helpers/loadJson.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs'; 2 | import { IdentityData, EgoData } from '@/types/data'; 3 | import path from 'path'; 4 | 5 | const ID_JSON = "identities.json" 6 | const EGO_JSON = "egos.json" 7 | 8 | export async function importIdentities() : Promise { 9 | const idFile = path.join(process.cwd(), 'public', ID_JSON); 10 | const data = await fs.readFile(idFile, "utf-8"); 11 | const identities = JSON.parse(data); 12 | 13 | return fixIdStringCosts(identities); 14 | } 15 | export async function importEgos() : Promise { 16 | const egoFile = path.join(process.cwd(), 'public', EGO_JSON); 17 | const data = await fs.readFile(egoFile, "utf-8"); 18 | const egos = JSON.parse(data); 19 | 20 | return fixEgoStringCosts(egos); 21 | } 22 | 23 | 24 | /** 25 | * Extra type casting for the numbers to be safe. 26 | * The JSONs should be correct but slips have happened before. 27 | */ 28 | function fixIdStringCosts(ids: IdentityData[]) : IdentityData[] { 29 | for (const id of ids) { 30 | id.active.cost = Number(id.active.cost); 31 | id.passive.cost = Number(id.passive.cost); 32 | 33 | for (const skill of id.skills) { 34 | skill.base = Number(skill.base); 35 | skill.plus = Number(skill.plus); 36 | skill.coins = Number(skill.coins); 37 | } 38 | } 39 | return ids; 40 | } 41 | function fixEgoStringCosts(egos: EgoData[]) : EgoData[] { 42 | for (const ego of egos) { 43 | for (const sinCost of ego.costs) { 44 | sinCost.cost = Number(sinCost.cost); 45 | } 46 | } 47 | return egos; 48 | } 49 | -------------------------------------------------------------------------------- /components/EgoComponent.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | @use 'mixins'; 3 | 4 | $ego-row-height: 28px; 5 | $item-border: 1px solid vars.$board-light; 6 | 7 | .container { 8 | position: relative; 9 | @include mixins.hover-focus-highlight(true); 10 | 11 | &:hover, &:focus { 12 | border: none; 13 | &::before { 14 | border-radius: 0 0 5px 5px; 15 | } 16 | } 17 | } 18 | .inactive { 19 | &:not(:hover, :focus) { 20 | @include mixins.gray-filter; 21 | } 22 | } 23 | 24 | .ego-row { 25 | display: flex; 26 | align-items: center; 27 | gap: 0.5rem; 28 | justify-content: space-between; 29 | 30 | width: 100%; 31 | aspect-ratio: vars.getSinnerCardAspectRatio($ego-row-height); 32 | 33 | border-top: $item-border; 34 | } 35 | 36 | .char-block { 37 | display: flex; 38 | flex-basis: 0; 39 | 40 | justify-content: center; 41 | align-items: center; 42 | 43 | height: 96%; 44 | min-width: 12%; 45 | 46 | background: vars.$board-light; 47 | border-radius: 0 4px 4px 0; 48 | 49 | img { 50 | height: 75%; 51 | } 52 | } 53 | 54 | .ego-name { 55 | color: vars.$grey; 56 | color: vars.$text-brown; 57 | font-size: vars.pxToRem(18px); 58 | line-height: $ego-row-height; 59 | 60 | overflow: hidden; 61 | text-overflow: ellipsis; 62 | white-space: nowrap; 63 | 64 | @media(max-width: vars.$small-screen) { 65 | font-size: vars.pxToRem(16px); 66 | } 67 | 68 | mix-blend-mode: exclusion; 69 | } 70 | 71 | .ego-img { 72 | object-fit: cover; 73 | height: 98%; 74 | aspect-ratio: 1; 75 | } 76 | 77 | .insufficient { 78 | color: vars.$grey; 79 | img { 80 | @include mixins.gray-filter; 81 | } 82 | } -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import '../styles/globals.scss' 3 | import { AppProps } from 'next/app' 4 | import { TeamProvider } from 'hooks/teamContext'; 5 | 6 | export default function MyApp({ Component, pageProps }: AppProps) { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | 16 | Limbus Company Team Builder 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {/* Worry about this later if doing PWA. 30 | 31 | */} 32 | 33 | 34 | 35 | 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /types/data.ts: -------------------------------------------------------------------------------- 1 | export const SINNER_NUMBERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13] as const 2 | export const SINS = ["Wrath", "Lust", "Sloth", "Gluttony", "Gloom", "Pride", "Envy"] as const 3 | export const EGO_RARITIES = ["ZAYIN", "TETH", "HE", "WAW", "ALEPH"] as const; 4 | export const ATTACK_TYPES = ["Slash", "Blunt", "Pierce"]; 5 | export const DEFENSE_TYPES = ["Guard", "Dodge", "Counter"] 6 | 7 | export type SinnerNumber = typeof SINNER_NUMBERS[number]; 8 | export type Sin = typeof SINS[number] 9 | export type AttackType = typeof ATTACK_TYPES[number]; 10 | export type DefenseType = typeof DEFENSE_TYPES[number]; 11 | export type EgoRarity = typeof EGO_RARITIES[number] 12 | export type Activation = "Owned" | "Res"; 13 | 14 | export interface TeamMember { 15 | sinner: SinnerNumber; 16 | id: IdentityData; 17 | egos: EgoData[]; 18 | active: boolean; 19 | } 20 | 21 | export type TeamResources = Map; 22 | 23 | export interface IdentityData { 24 | sinner: SinnerNumber; 25 | name: string; 26 | rarity: 1 | 2 | 3; 27 | active: Passive; 28 | passive: Passive; 29 | skills: Skill[]; 30 | filename?: string; 31 | } 32 | 33 | export interface EgoData { 34 | sinner: SinnerNumber; 35 | name: string; 36 | rarity: EgoRarity; 37 | affinity: Sin; 38 | type: AttackType; 39 | costs: EgoCost[] 40 | filename?: string; 41 | } 42 | 43 | export interface Passive { 44 | affinity: Sin; 45 | cost: number; 46 | activation: Activation; 47 | } 48 | 49 | export interface EgoCost { 50 | affinity: Sin; 51 | cost: number; 52 | } 53 | 54 | export interface Skill { 55 | affinity: Sin; 56 | base: number; 57 | plus: number; 58 | coins: number; 59 | type: AttackType | DefenseType 60 | } 61 | -------------------------------------------------------------------------------- /styles/globals.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | @use 'mixins'; 3 | @use 'normalize.css/normalize.css'; 4 | 5 | 6 | /** 7 | * Reset/Defaults. 8 | */ 9 | html, 10 | body { 11 | padding: 0; 12 | margin: 0; 13 | 14 | color: vars.$text-brown; 15 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 16 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 17 | 18 | background: vars.$page-bg; 19 | 20 | @include mixins.orange-scrollbar; 21 | &::-webkit-scrollbar { 22 | // Please note BODY_SCROLLBAR_WIDTH in modal tsx file when changing this. 23 | width: 8px; 24 | } 25 | &::-webkit-scrollbar-thumb, &::-webkit-scrollbar-track { 26 | border-radius: 0; 27 | } 28 | @media (max-width: vars.$small-screen) { 29 | &::-webkit-scrollbar-thumb, &::-webkit-scrollbar-track { 30 | border-radius: 0; 31 | } 32 | } 33 | } 34 | 35 | a { 36 | color: vars.$text-yellow; 37 | 38 | &:visited { 39 | color: vars.$grey; 40 | } 41 | 42 | &:hover { 43 | color: vars.$orange-highlight; 44 | } 45 | 46 | &:active { 47 | outline: none; 48 | color: vars.$orange-highlight; 49 | } 50 | } 51 | 52 | p, h1, h2, h3, h4, h5, ul, ol, menu { 53 | margin: 0; 54 | padding: 0; 55 | } 56 | 57 | ol, ul, menu { 58 | list-style-type: none 59 | } 60 | 61 | input[type="checkbox"] { 62 | appearance: none; 63 | 64 | display: grid; 65 | place-content: center; 66 | margin: 0; 67 | 68 | color: vars.$blood-red; 69 | background-color: vars.$page-bg;; 70 | } 71 | input[type="checkbox"]::before { 72 | content: "✘"; 73 | transform: scale(0); 74 | } 75 | input[type="checkbox"]:checked::before { 76 | transform: scale(1); 77 | } 78 | 79 | * { 80 | box-sizing: border-box; 81 | &:focus:not(:focus-visible) { 82 | outline: none; 83 | } 84 | } 85 | 86 | 87 | /** 88 | * Global reusable. 89 | */ 90 | .board { 91 | background: vars.$board-bg; 92 | border: 2px solid vars.$board-light; 93 | border-radius: 20px; 94 | } 95 | .board-dark { 96 | @extend .board; 97 | background: vars.$page-bg; 98 | } 99 | -------------------------------------------------------------------------------- /components/TeamBoard.tsx: -------------------------------------------------------------------------------- 1 | import { memo } from 'react'; 2 | import SinnerCard, { SinnerCardProps } from '@/components/SinnerCard'; 3 | import { useTeamContext, useTeamDispatchContext } from '@/hooks/teamContext'; 4 | import { SINNER_NUMBERS, SinnerNumber, IdentityData, EgoData } from '@/types/data'; 5 | 6 | import styles from './TeamBoard.module.scss'; 7 | 8 | 9 | // Important. Make sure the BOARD does NOT consume team context. 10 | // The individual components should unless we wanna enter the rerender blender zone. 11 | export default function TeamBoard({idData, egoData} : {idData: IdentityData[], egoData: EgoData[]}) { 12 | const sinnerCards = SINNER_NUMBERS.map((num) => SinnerCardForMember(SinnerCard, num)); 13 | 14 | return ( 15 |
16 | { sinnerCards.map((Card, index) => { 17 | const num = convertIndexToSinnerNum(index); 18 | return ( 19 | 23 | ) 24 | } 25 | )} 26 |
27 | ) 28 | } 29 | 30 | 31 | // Higher order component to use part of team context. 32 | // - Avoid ALL cards rerendering when one team member changes id/ego. 33 | function SinnerCardForMember(WrappedSinnerCard: React.ComponentType, sinner: SinnerNumber) { 34 | const MemoisedSinnerCard = memo(WrappedSinnerCard); 35 | 36 | const SinnerCardForMember = (props: any) => { 37 | const index = sinner >= 10 ? sinner - 2 : sinner - 1; 38 | const member = useTeamContext()[index]; 39 | 40 | return ( 41 | 42 | ) 43 | } 44 | SinnerCardForMember.displayName = `SinnerCardForMember-${sinner}` 45 | 46 | return SinnerCardForMember; 47 | } 48 | 49 | 50 | function filterIdData(sinner: SinnerNumber) { 51 | return (data: IdentityData) => data.sinner == sinner; 52 | } 53 | 54 | function filterEgoData(sinner: SinnerNumber) { 55 | return (data: EgoData) => data.sinner == sinner; 56 | } 57 | 58 | function convertIndexToSinnerNum(index: number) : SinnerNumber { 59 | const res = index <= 8 ? index + 1 : index + 2; 60 | return res as SinnerNumber; 61 | } -------------------------------------------------------------------------------- /components/EgoCostSummary.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | @use 'mixins'; 3 | 4 | $ego-img-width: 120px; 5 | $ego-img-width-mobile: 75px; 6 | 7 | $name-max-width: 250px; 8 | $sin-icon-width: 32px; 9 | $sin-icon-width-mobile: 22px; 10 | 11 | .container { 12 | margin-top: 3rem; 13 | padding: 10px; 14 | } 15 | 16 | .member-egos-container { 17 | display: flex; 18 | flex-wrap: wrap; 19 | align-items: stretch; 20 | gap: 0.5rem; 21 | } 22 | 23 | .member-ego-container { 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | row-gap: 1.5rem; 28 | 29 | padding: 1rem; 30 | 31 | overflow: hidden; 32 | } 33 | 34 | .ego-container { 35 | display: flex; 36 | align-items: center; 37 | 38 | p { 39 | max-width: $name-max-width; 40 | margin-bottom: 0.5rem; 41 | 42 | line-height: 1.3; 43 | color: vars.$text-yellow; 44 | font-size: vars.pxToRem(20px); 45 | @media (max-width: vars.$mobile-screen) { 46 | font-size: vars.pxToRem(12px); 47 | } 48 | 49 | white-space: nowrap; 50 | overflow: hidden; 51 | text-overflow: ellipsis; 52 | } 53 | } 54 | .ego-insufficient { 55 | .ego-img-container, p { 56 | @include mixins.gray-filter; 57 | color: vars.$grey; 58 | } 59 | } 60 | 61 | .ego-img-container { 62 | position: relative; // ref for absolute position p. 63 | margin-right: 1rem; 64 | 65 | isolation: isolate; 66 | background: linear-gradient( 67 | #FFFFFF00 60%, 68 | #{vars.$page-bg} 69 | ); 70 | 71 | img { 72 | width: $ego-img-width; 73 | @media (max-width: vars.$mobile-screen) { 74 | width: $ego-img-width-mobile; 75 | } 76 | mix-blend-mode: overlay; 77 | } 78 | } 79 | 80 | .ego-costs-container{ 81 | display: grid; 82 | grid-template-columns: 1fr 1fr 1fr; 83 | gap: 1rem; 84 | @media (max-width: vars.$mobile-screen) { 85 | gap: 0.25rem; 86 | } 87 | } 88 | 89 | .ego-cost-pair { 90 | display: flex; 91 | align-items: center; 92 | 93 | img { 94 | width: $sin-icon-width; 95 | margin-right: 0.5rem; 96 | @media (max-width: vars.$mobile-screen) { 97 | width: $sin-icon-width-mobile; 98 | } 99 | } 100 | 101 | font-size: vars.pxToRem(18px); 102 | @media (max-width: vars.$mobile-screen) { 103 | font-size: vars.pxToRem(14px); 104 | } 105 | } 106 | .cost-insufficient { 107 | color: vars.$text-red; 108 | } -------------------------------------------------------------------------------- /components/EgoCostSummary.tsx: -------------------------------------------------------------------------------- 1 | import { useTeamContext, useTeamResourcesContext } from '@/hooks/teamContext'; 2 | import { getSinTypeAsset } from '@/helpers/assets'; 3 | import { getSinnerEgoSrcImg } from '@/helpers/sinnerData'; 4 | import { egoSufficient } from '@/helpers/costCalcs'; 5 | import { EgoData, Sin } from '@/types/data'; 6 | 7 | import styles from './EgoCostSummary.module.scss'; 8 | 9 | export default function EgoCostsSummary() { 10 | const team = useTeamContext(); 11 | const resources = useTeamResourcesContext(); 12 | 13 | const activeMembers = team.filter((mem) => mem.active); 14 | let none = true; 15 | for (const mem of activeMembers) { 16 | if (mem.egos.length > 0) { 17 | none = false; 18 | break; 19 | } 20 | } 21 | if (none) return null; 22 | 23 | function sinSufficient(sin: Sin, cost: number) { 24 | const res = resources.get(sin) ?? 0; 25 | return cost <= res; 26 | } 27 | 28 | function egoContainer(ego: EgoData) { 29 | const sufficient = egoSufficient(resources, ego); 30 | return ( 31 |
33 |
34 | {ego.name}/ 36 |
37 |
38 |

{ego.name}

39 |
40 | { ego.costs.map((cost) => 41 |
44 | {cost.affinity}/ 46 | {`x${resources.get(cost.affinity) ?? 0}/${cost.cost}`} 47 |
48 | )} 49 |
50 |
51 |
52 | ) 53 | } 54 | 55 | return ( 56 |
57 |
58 | { activeMembers.map((member) => 59 |
60 | { member.egos.map((ego) => 61 | egoContainer(ego) 62 | )} 63 |
64 | )} 65 |
66 |
67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /helpers/assets.ts: -------------------------------------------------------------------------------- 1 | import { DEFENSE_TYPES, AttackType, DefenseType, Sin, EgoRarity } from '@/types/data'; 2 | import css from './assets.module.scss'; 3 | 4 | 5 | function getRarityAsset(rarity: number) { 6 | return `assets/${rarity}star.webp`; 7 | } 8 | 9 | function getSkillTypeAsset(type: AttackType | DefenseType, defense: boolean) { 10 | if (defense && !DEFENSE_TYPES.includes(type)) { 11 | type = "counter"; 12 | } 13 | return `assets/${type.toLowerCase()}.webp`; 14 | } 15 | 16 | function getSinTypeHexAsset(affinity?: Sin) { 17 | const name = affinity ? affinity : "none"; 18 | return `assets/hex-${name.toLowerCase()}.svg`; 19 | } 20 | 21 | function getSinTypeAsset(sin: Sin) { 22 | switch(sin) { 23 | case 'Wrath': return 'assets/wrath.webp'; 24 | case 'Lust': return 'assets/lust.webp'; 25 | case 'Sloth': return 'assets/sloth.webp'; 26 | case 'Gluttony': return 'assets/gluttony.webp'; 27 | case 'Gloom': return 'assets/gloom.webp'; 28 | case 'Pride': return 'assets/pride.webp'; 29 | case 'Envy': return 'assets/envy.webp'; 30 | } 31 | } 32 | 33 | function getSinCSSColor(sin: Sin, alpha: number=255) { 34 | let color = ""; 35 | switch(sin) { 36 | case 'Wrath': color = css.wrath; break; 37 | case 'Lust': color = css.lust; break; 38 | case 'Sloth': color = css.sloth; break; 39 | case 'Gluttony': color = css.gluttony; break; 40 | case 'Gloom': color = css.gloom; break; 41 | case 'Pride': color = css.pride; break; 42 | case 'Envy': color = css.envy; break; 43 | } 44 | 45 | return color + alpha.toString(16); 46 | } 47 | 48 | function getEgoRarityAsset(egoRarity: EgoRarity, bright : boolean=false) { 49 | let name; 50 | switch(egoRarity) { 51 | case "ZAYIN": name = "zayin"; break; 52 | case "TETH": name = "teth"; break; 53 | case "HE": name = "he"; break; 54 | case "WAW": name = "waw"; break; 55 | case "ALEPH": name = "aleph"; break; 56 | } 57 | if (bright) name += "-bright" 58 | 59 | return `assets/${name}.webp`; 60 | } 61 | 62 | function getEgoRarityLabelAsset(egoRarity: EgoRarity, bright : boolean=false) { 63 | let name; 64 | switch(egoRarity) { 65 | case "ZAYIN": name = "zayin"; break; 66 | case "TETH": name = "teth"; break; 67 | case "HE": name = "he"; break; 68 | case "WAW": name = "waw"; break; 69 | case "ALEPH": name = "aleph"; break; 70 | } 71 | 72 | return `assets/${name}-label.webp`; 73 | } 74 | 75 | 76 | 77 | export { 78 | getRarityAsset, 79 | getEgoRarityAsset, getEgoRarityLabelAsset, 80 | getSkillTypeAsset, 81 | getSinTypeHexAsset, 82 | getSinTypeAsset, 83 | getSinCSSColor, 84 | } -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Noto_Sans_KR } from 'next/font/google' 2 | import { GetStaticPropsContext } from 'next'; 3 | import { useEffect } from 'react'; 4 | import { useTeamDispatchContext, TeamDispatchFunctions, EgoDispatchFunctions } from '@/hooks/teamContext'; 5 | import TeamBoard from '@/components/TeamBoard'; 6 | import Button from '@/components/Button'; 7 | import AffinitySummary from '@/components/AffinitySummary'; 8 | import EgoCostsSummary from '@/components/EgoCostSummary'; 9 | import Footer from '@/components/Footer'; 10 | import { importEgos, importIdentities } from '@/helpers/loadJson'; 11 | import { egoSort, idSort } from '@/helpers/sinnerData'; 12 | import { SINNER_NUMBERS, IdentityData, EgoData } from '@/types/data'; 13 | import styles from '../styles/index.module.scss'; 14 | 15 | 16 | const NotoSansKR = Noto_Sans_KR({ 17 | weight: ['400', '700'], 18 | subsets: ['latin'], 19 | }) 20 | 21 | 22 | interface HomeProps { 23 | idData : IdentityData[]; 24 | egoData: EgoData[]; 25 | } 26 | 27 | export default function Index({idData, egoData} : HomeProps) { 28 | const teamDispatch = useTeamDispatchContext(); 29 | const [setActive, updateId] = TeamDispatchFunctions(teamDispatch) 30 | const [_, setEgos] = EgoDispatchFunctions(teamDispatch); 31 | 32 | const sortedIds = idData.sort(idSort); 33 | const sortedEgos = egoData.sort(egoSort); 34 | 35 | // Set initial team. 36 | useEffect(() => { 37 | setInitialTeam(); 38 | }, []) 39 | 40 | function setInitialTeam() { 41 | for (const num of SINNER_NUMBERS) { 42 | const firstId = sortedIds.find((id) => id.sinner === num); 43 | if (firstId) updateId(firstId); 44 | 45 | const firstEgo = sortedEgos.find((ego) => ego.sinner === num); 46 | if (firstEgo) setEgos([firstEgo]); 47 | 48 | // Let Yi Sang be active to show how it works. 49 | setActive(num, num === 1); 50 | } 51 | } 52 | 53 | return ( 54 |
55 | 56 |
57 | 60 |
61 | 62 | 63 |
64 |
65 | ) 66 | } 67 | 68 | 69 | // We can actually import the JSON directly, but this makes it easier to 70 | // change if we want to import from somewhere else for each weekly update. 71 | export async function getStaticProps(context: GetStaticPropsContext) { 72 | const identities = await importIdentities(); 73 | const egos = await importEgos(); 74 | 75 | return { 76 | props: { 77 | idData: identities, 78 | egoData: egos, 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /.github/workflows/nextjs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Next.js site to Pages 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 11 | permissions: 12 | contents: read 13 | pages: write 14 | id-token: write 15 | 16 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 17 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 18 | concurrency: 19 | group: "pages" 20 | cancel-in-progress: false 21 | 22 | jobs: 23 | # Build job 24 | build: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v3 29 | - name: Setup pnpm 30 | uses: pnpm/action-setup@v2.2.4 31 | with: 32 | version: 8 33 | - name: Setup Node 34 | uses: actions/setup-node@v3 35 | with: 36 | node-version: "16" 37 | cache: 'pnpm' 38 | - name: Setup Pages 39 | uses: actions/configure-pages@v3 40 | with: 41 | # Automatically inject basePath in your Next.js configuration file and disable 42 | # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized). 43 | # 44 | # You may remove this line if you want to manage the configuration yourself. 45 | static_site_generator: next 46 | - name: Restore cache 47 | uses: actions/cache@v3 48 | with: 49 | path: | 50 | .next/cache 51 | # Generate a new cache whenever packages or source files change. 52 | key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} 53 | # If source files changed but packages didn't, rebuild from a prior cache. 54 | restore-keys: | 55 | ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/[pnpm-lock.yaml]') }}- 56 | - name: Install dependencis 57 | run: pnpm install --frozen-lockfile 58 | - name: Build with Next.js 59 | run: pnpm next build 60 | - name: Static HTML export with Next.js 61 | run: pnpm next export 62 | - name: Upload artifact 63 | uses: actions/upload-pages-artifact@v1 64 | with: 65 | path: ./out 66 | 67 | # Deployment job 68 | deploy: 69 | environment: 70 | name: github-pages 71 | url: ${{ steps.deployment.outputs.page_url }} 72 | runs-on: ubuntu-latest 73 | needs: build 74 | steps: 75 | - name: Deploy to GitHub Pages 76 | id: deployment 77 | uses: actions/deploy-pages@v2 78 | -------------------------------------------------------------------------------- /components/EgoComponent.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { useTeamResourcesContext, useTeamDispatchContext, EgoDispatchFunctions } from '@/hooks/teamContext'; 3 | import EgoSelection from '@/components/EgoSelection'; 4 | import { getSinCSSColor, getEgoRarityAsset } from '@/helpers/assets'; 5 | import { getSinnerEgoSrcImg } from '@/helpers/sinnerData' 6 | import { egoSufficient } from '@/helpers/costCalcs' 7 | import { TeamMember, EgoData, EgoRarity, EGO_RARITIES } from '@/types/data'; 8 | import styles from './EgoComponent.module.scss'; 9 | 10 | interface EgoComponentProps { 11 | member: TeamMember; 12 | egoData : EgoData[]; 13 | } 14 | 15 | export default function EgoComponent({member, egoData} : EgoComponentProps) { 16 | const memberEgos = member.egos; 17 | 18 | const resources = useTeamResourcesContext(); 19 | const dispatch = useTeamDispatchContext(); 20 | const [egoSelected] = EgoDispatchFunctions(dispatch); 21 | 22 | const [showEgoModal, setShowEgoModal] = useState(false); 23 | 24 | function getEgo(rarity: EgoRarity) { 25 | return memberEgos?.find((ego) => ego.rarity === rarity); 26 | } 27 | 28 | function handleKeyDown(e: React.KeyboardEvent) { 29 | if (e.key == 'Enter') { 30 | e.preventDefault(); 31 | setShowEgoModal(!showEgoModal); 32 | } 33 | } 34 | 35 | function egoRow(egoRarity: EgoRarity) { 36 | const ego = getEgo(egoRarity); 37 | const sufficient = egoSufficient(resources, ego); 38 | 39 | return ( 40 |
ego ? egoSelected(ego) : {} }> 43 |
44 | {egoRarity}/ 46 |
47 |
49 | { ego?.name } 50 |
51 | { ego && 52 | {ego.name}/ 55 | } 56 |
57 | ) 58 | } 59 | 60 | return ( 61 | <> 62 | {/* Modals -- layout independent of rest of content. */} 63 | { showEgoModal && 65 | } 66 |
setShowEgoModal(!showEgoModal)} 70 | onMouseDown={e => e.preventDefault()}> 71 | { EGO_RARITIES.map((item) => egoRow(item)) } 72 |
73 | 74 | ) 75 | } 76 | -------------------------------------------------------------------------------- /styles/_mixins.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | 3 | // Mixins 4 | // - Prefer mixin instead of something in globals if there a tendency 5 | // to override something from the mixin a little bit or 6 | // add a little extra (easier to read in the css file). 7 | @mixin hover-focus-highlight($before-border: false) { 8 | &:hover, &:focus { 9 | cursor: pointer; 10 | outline: none; 11 | 12 | @include highlight-effect; 13 | 14 | @if $before-border == true { 15 | @include highlight-before-border; 16 | border: none; 17 | } 18 | } 19 | } 20 | 21 | @mixin highlight-before-border { 22 | &::before { 23 | content: ""; 24 | position: absolute; 25 | top: 0; 26 | bottom: 0; 27 | left: 0; 28 | right: 0; 29 | border: 4px solid vars.$orange-highlight; 30 | 31 | z-index: vars.$before-highlight-border-z; 32 | } 33 | } 34 | 35 | @mixin highlight-effect { 36 | color: vars.$orange-highlight; 37 | border: 2px solid vars.$orange-highlight; 38 | 39 | &::after { 40 | content: ""; 41 | position: absolute; 42 | top: 0; 43 | bottom: 0; 44 | left: 0; 45 | right: 0; 46 | 47 | background: vars.$orange-highlight; 48 | opacity: 0.3; 49 | mix-blend-mode: overlay; 50 | 51 | // Prefer mix-blend-mode otherwise you get "pointy corners" 52 | // if element has border-radius. 53 | @supports not (mix-blend-mode: overlay) { 54 | opacity: 0.15; 55 | background: vars.$orange-highlight; 56 | } 57 | 58 | } 59 | } 60 | 61 | @mixin gray-filter($strength: 0.8) { 62 | filter: grayscale($strength); 63 | 64 | // Grayscale is what we actually want. 65 | // Overlay is for old brows. 66 | @supports not (filter: grayscale(1)) { 67 | &::after { 68 | content: ""; 69 | position: absolute; 70 | top: 0; 71 | bottom: 0; 72 | left: 0; 73 | right: 0; 74 | 75 | opacity: 0.66; 76 | background: vars.$grey; 77 | } 78 | } 79 | } 80 | 81 | $scrollbar-w: 6px; 82 | $scrollbar-w-mobile: 3px; 83 | 84 | @mixin orange-scrollbar { 85 | @supports not(selector(::-webkit-scrollbar)) { 86 | scrollbar-width: thin; 87 | scrollbar-color: vars.$orange-highlight vars.$grey; 88 | } 89 | 90 | &::-webkit-scrollbar { 91 | width: $scrollbar-w; 92 | } 93 | &::-webkit-scrollbar-thumb { /* Foreground */ 94 | border-radius: $scrollbar-w; 95 | background: vars.$orange-highlight; 96 | } 97 | &::-webkit-scrollbar-track { /* Background */ 98 | border-radius: $scrollbar-w; 99 | background: vars.$grey; 100 | } 101 | 102 | @media (max-width: vars.$small-screen) { 103 | &::-webkit-scrollbar { 104 | width: $scrollbar-w-mobile; 105 | } 106 | &::-webkit-scrollbar-thumb { 107 | border-radius: $scrollbar-w-mobile; 108 | } 109 | &::-webkit-scrollbar-track { 110 | border-radius: $scrollbar-w-mobile; 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /helpers/sinnerData.ts: -------------------------------------------------------------------------------- 1 | import { EGO_RARITIES, IdentityData, EgoData } from "@/types/data"; 2 | 3 | function sinnerNumberToName(number: number, caps: boolean=false) { 4 | switch(number) { 5 | case 1: return caps ? "Yi Sang" : "yi sang"; 6 | case 2: return caps ? "Faust" : "faust"; 7 | case 3: return caps ? "Don Quixote" : "don quixote"; 8 | case 4: return caps ? "Ryoshu" : "ryoshu"; 9 | case 5: return caps ? "Meursault" : "meursault"; 10 | case 6: return caps ? "Hong Lu" : "hong lu"; 11 | case 7: return caps ? "HeathCliff" : "heathcliff"; 12 | case 8: return caps ? "Ishmael" : "ishmael"; 13 | case 9: return caps ? "Rodion" : "rodion"; 14 | case 10: return caps ? "Dante" : "dante"; 15 | case 11: return caps ? "Sinclair" : "sinclair"; 16 | case 12: return caps ? "Outis" : "outis"; 17 | case 13: return caps ? "Gregor" : "gregor"; 18 | } 19 | } 20 | 21 | function getSinnerEgoSrcImg(ego: EgoData) { 22 | const sinner = sinnerNumberToName(ego.sinner); 23 | 24 | // Special case for some egos with chars unusable in filenames. 25 | if (ego.filename) { 26 | return `sinners/${sinner}/ego/${ego.filename}.webp`; 27 | } 28 | 29 | const egoName = ego.name.toLowerCase().trim(); 30 | return `sinners/${sinner}/ego/${egoName}.webp`; 31 | } 32 | 33 | function getSinnerIdSrcImg(id: IdentityData) { 34 | const sinner = sinnerNumberToName(id.sinner); 35 | 36 | // Special case for some egos with chars unusable in filenames. 37 | if (id.filename) { 38 | return `sinners/${sinner}/identities/${id.filename}.webp`; 39 | } 40 | 41 | const idName = id.name.toLocaleLowerCase().trim(); 42 | return `sinners/${sinner}/identities/${idName}.webp`; 43 | } 44 | 45 | function identityEquals(a?: IdentityData, b?: IdentityData) { 46 | if (!a || !b) return false; 47 | 48 | // TODO: Use ids instead of name compares 49 | return a.name === b.name; 50 | } 51 | 52 | function egoEquals(a?: EgoData, b?: EgoData) { 53 | if (!a || !b) return false; 54 | 55 | // TODO: Use ids instead of name compares 56 | return a.name === b.name; 57 | } 58 | 59 | function egoSort(egoA: EgoData, egoB: EgoData) { 60 | if (!egoA && !egoB) return 0; 61 | if (!egoA) return 1; 62 | if (!egoB) return -1; 63 | 64 | if (egoA.sinner < egoB.sinner) return -1; 65 | if (egoB.sinner < egoA.sinner) return 1; 66 | 67 | const rarA = EGO_RARITIES.indexOf(egoA.rarity); 68 | const rarB = EGO_RARITIES.indexOf(egoB.rarity); 69 | if (rarA < rarB) return -1; 70 | if (rarB < rarA) return 1; 71 | 72 | return 0; 73 | } 74 | 75 | function idSort(idA: IdentityData, idB: IdentityData) { 76 | if (!idA && !idB) return 0; 77 | if (!idA) return 1; 78 | if (!idB) return -1; 79 | 80 | if (idA.sinner < idB.sinner) return -1; 81 | if (idB.sinner < idA.sinner) return 1; 82 | 83 | if (idA.rarity < idB.rarity) return -1; 84 | if (idB.rarity < idA.rarity) return 1; 85 | 86 | return idA.name.localeCompare(idB.name); 87 | } 88 | 89 | 90 | export { 91 | sinnerNumberToName, 92 | getSinnerEgoSrcImg, getSinnerIdSrcImg, 93 | identityEquals, egoEquals, 94 | egoSort, idSort, 95 | } -------------------------------------------------------------------------------- /components/Modal.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { createPortal } from 'react-dom'; 3 | import styles from './Modal.module.scss' 4 | 5 | // Ensure only one modal open at a time; 6 | let modalIsOpen = false; 7 | const MODAL_ID = "THE-MODAL"; 8 | const BODY_SCROLLBAR_WIDTH = "8px" 9 | 10 | interface ModalProps { 11 | children: React.ReactNode; 12 | closeModal: () => void; 13 | } 14 | 15 | export default function Modal({children, closeModal} : ModalProps) { 16 | useEffect(() => { 17 | modalOpen(); 18 | return () => modalClosed(); 19 | }, []) 20 | 21 | function preventBubbleUp(e : React.MouseEvent) { 22 | e.stopPropagation(); 23 | } 24 | 25 | function handleKeydown(e: React.KeyboardEvent) { 26 | if (e.key == 'Escape') { 27 | e.preventDefault(); 28 | closeModal(); 29 | } 30 | } 31 | 32 | return ( 33 | <> 34 | { createPortal( 35 |
38 |
39 | {children} 40 |
41 |
, 42 | document.body 43 | )} 44 | 45 | ) 46 | } 47 | 48 | /** 49 | * Modal Open/Close 50 | * - Add overlay 51 | * - Prevent body scrolling 52 | * - Prevent interaction with things outside of modal. 53 | * = Extremely basic focus trap for our use case. 54 | * = We don't need to worry about accessibility for LC players. 55 | */ 56 | const FOCUSABLE = "input:not([disabled]), *[tabindex]"; 57 | let focusRemoved : [Element, string | null][] = [] ; 58 | let lastFocus : Element | null; 59 | 60 | function modalOpen() { 61 | modalIsOpen = true; 62 | if (!document) return; 63 | 64 | document.body.style.overflow = "hidden"; 65 | document.body.style.paddingRight = BODY_SCROLLBAR_WIDTH; 66 | const main = document.querySelector('main'); 67 | if (!main) return; 68 | 69 | const focusableElements = main.querySelectorAll(FOCUSABLE); 70 | focusableElements.forEach(elem => { 71 | if (document.activeElement === elem) lastFocus = elem; 72 | 73 | const original = elem.getAttribute("tabindex"); 74 | elem.setAttribute("tabindex", "-1"); 75 | focusRemoved.push([elem, original]) 76 | }); 77 | 78 | const modalElem = document.body.querySelector(`#${MODAL_ID}`); 79 | const modalFocusable = modalElem?.querySelector(FOCUSABLE); 80 | if (lastFocus) { 81 | (modalFocusable as HTMLElement)?.focus() 82 | } 83 | } 84 | 85 | function modalClosed() { 86 | modalIsOpen = false; 87 | if (!document) return; 88 | 89 | document.body.style.overflow = "unset"; 90 | document.body.style.paddingRight = "0px"; 91 | for (const [elem, original] of focusRemoved) { 92 | if (original) { 93 | elem.setAttribute("tabindex", original); 94 | } else { 95 | elem.removeAttribute("tabindex"); 96 | } 97 | } 98 | (lastFocus as HTMLElement)?.focus(); 99 | 100 | focusRemoved = []; 101 | lastFocus = null; 102 | } 103 | -------------------------------------------------------------------------------- /components/EgoSelection.tsx: -------------------------------------------------------------------------------- 1 | import { useTeamContext, useTeamDispatchContext, EgoDispatchFunctions } from '@/hooks/teamContext'; 2 | import Modal from '@/components/Modal'; 3 | import Button from '@/components/Button'; 4 | import { getSinnerEgoSrcImg, egoEquals } from '@/helpers/sinnerData'; 5 | import { getEgoRarityLabelAsset, getSinTypeAsset } from '@/helpers/assets' 6 | import { EgoData } from '@/types/data'; 7 | import styles from './EgoSelection.module.scss'; 8 | 9 | 10 | interface EgoSelectionProps { 11 | egoData : EgoData[]; 12 | setModalOpen: (open : boolean) => void; 13 | } 14 | 15 | export default function IdentitySelection({egoData, setModalOpen} : EgoSelectionProps) { 16 | const team = useTeamContext(); 17 | const teamDispatch = useTeamDispatchContext(); 18 | const [egoSelected] = EgoDispatchFunctions(teamDispatch); 19 | 20 | const sinner = egoData[0]?.sinner; 21 | const activeEgos = team.find((member) => member.sinner === sinner)?.egos; 22 | 23 | const handleKeyDown = (e: React.KeyboardEvent, ego: EgoData) => { 24 | if (e.key === 'Enter') { 25 | e.preventDefault(); 26 | egoSelected(ego); 27 | } 28 | } 29 | 30 | function egoCard(ego: EgoData) { 31 | const active = activeEgos?.find((activeEgo) => egoEquals(activeEgo, ego)) !== undefined; 32 | 33 | return ( 34 |
35 |
egoSelected(ego)} 38 | onKeyDown={ (e) => handleKeyDown(e, ego)} 39 | tabIndex={0} 40 | onMouseDown={e => e.preventDefault()}> 41 | {String(ego.rarity)}/ 44 | {String(ego.affinity)}/ 47 |
48 | {`picture 51 |
52 |

{ego.name}

53 |
54 | { ego.costs.map((cost, index) => 55 |
56 | {cost.affinity}/ 57 |

{`x${cost.cost}`}

58 |
59 | )} 60 |
61 |
62 |
63 | ) 64 | } 65 | 66 | return ( 67 | setModalOpen(false)}> 68 |
69 | 72 |
73 | { egoData.map((ego) => egoCard(ego))} 74 |
75 | 78 |
79 |
80 | ) 81 | } 82 | -------------------------------------------------------------------------------- /components/IdentitySelection.tsx: -------------------------------------------------------------------------------- 1 | import { useTeamContext, useTeamDispatchContext, TeamDispatchFunctions } from '@/hooks/teamContext'; 2 | import Modal from '@/components/Modal'; 3 | import Button from '@/components/Button'; 4 | import { getSinnerIdSrcImg, identityEquals } from '@/helpers/sinnerData'; 5 | import { getRarityAsset, getSinTypeAsset } from '@/helpers/assets' 6 | import { IdentityData } from '@/types/data'; 7 | import styles from './IdentitySelection.module.scss'; 8 | 9 | 10 | interface IdSelectionProps { 11 | idData : IdentityData[]; 12 | setModalOpen: (open : boolean) => void; 13 | } 14 | 15 | // Use setIdentity instead of just SinnerCard consuming context is just to prevent rerendering all 12 cards. 16 | // More of an exercise -- it's actually super fast either way. 17 | export default function IdentitySelection({idData, setModalOpen} : IdSelectionProps) { 18 | const team = useTeamContext(); 19 | const teamDispatch = useTeamDispatchContext(); 20 | const [_, updateId] = TeamDispatchFunctions(teamDispatch); 21 | 22 | const sinner = idData[0]?.sinner; 23 | const activeId = team.find((member) => member.sinner === sinner)?.id; 24 | 25 | function setId(id: IdentityData) { 26 | setModalOpen(false); 27 | updateId(id); 28 | } 29 | 30 | const handleKeyDown = (e: React.KeyboardEvent, id: IdentityData) => { 31 | if (e.key === 'Enter') { 32 | e.preventDefault(); 33 | setId(id); 34 | } 35 | } 36 | 37 | function idCard(identity: IdentityData) { 38 | const active = identityEquals(identity, activeId); 39 | 40 | return ( 41 |
setId(identity)} 44 | onMouseDown={e => e.preventDefault()} 45 | tabIndex={0} 46 | onKeyDown={ (e) => handleKeyDown(e, identity)}> 47 |
48 | {String(identity.rarity)}/ 51 |
52 |

{identity.name}

53 |
54 | {`picture 57 |
58 |
59 | { identity.skills.map((skill, index) => 60 | index < 3 && 61 |
62 | {skill.affinity}/ 63 |

{`x${3-index}`}

64 |
65 | )} 66 |
67 |
68 | ) 69 | } 70 | 71 | return ( 72 | setModalOpen(false)}> 73 |
74 | 77 |
78 | { idData.map((identity) => idCard(identity))} 79 |
80 | 83 |
84 |
85 | ) 86 | } 87 | -------------------------------------------------------------------------------- /components/AffinitySummary.tsx: -------------------------------------------------------------------------------- 1 | import { useTeamContext, useTeamResourcesContext } from '@/hooks/teamContext'; 2 | import SkillHexagon from '@/components/SkillHexagon'; 3 | import { getSinTypeAsset } from '@/helpers/assets' 4 | import { getEgoResourcesMap } from '@/helpers/costCalcs' 5 | import { SINS, ATTACK_TYPES, AttackType, EgoData, TeamResources } from '@/types/data'; 6 | 7 | import styles from './AffinitySummary.module.scss'; 8 | 9 | 10 | export default function AffinitySummary() { 11 | return ( 12 | <> 13 | 14 | 15 | 16 | ) 17 | } 18 | 19 | function SkillSummaryBoard() { 20 | const team = useTeamContext(); 21 | const teamResources = useTeamResourcesContext(); 22 | 23 | let slash = 0; 24 | let blunt = 0; 25 | let pierce = 0; 26 | for (const member of team) { 27 | if (!member.active) continue; 28 | 29 | member.id.skills.forEach((skill) => { 30 | const attackType = skill.type; 31 | switch (attackType) { 32 | case "Slash": slash += 1; break; 33 | case "Blunt": blunt += 1; break; 34 | case "Pierce": pierce += 1; break; 35 | } 36 | }) 37 | } 38 | 39 | function attackCount(attackType : AttackType) { 40 | switch (attackType) { 41 | case "Slash": return slash; 42 | case "Blunt": return blunt; 43 | case "Pierce": return pierce 44 | default: return 0; 45 | } 46 | } 47 | 48 | 49 | return ( 50 |
51 |

ATK AFFINITIES:

52 |
53 | { SINS.map((sin) => 54 |
55 | {sin}/ 56 | {`x${teamResources.get(sin) ?? 0}`} 57 |
58 | )} 59 |
60 |
61 | { ATTACK_TYPES.map((attack) => 62 |
63 | 64 | {`x${attackCount(attack)}`} 65 |
66 | )} 67 |
68 |
69 | ) 70 | } 71 | 72 | function EgoSummaryBoard() { 73 | const team = useTeamContext(); 74 | 75 | const activeMemberEgos : EgoData[] = []; 76 | for (const member of team) { 77 | if (member.active) { 78 | activeMemberEgos.push(...member.egos); 79 | } 80 | } 81 | 82 | const egoResources = getEgoResourcesMap(activeMemberEgos); 83 | 84 | let slash = 0; 85 | let blunt = 0; 86 | let pierce = 0; 87 | for (const ego of activeMemberEgos) { 88 | switch (ego.type) { 89 | case "Slash": slash += 1; break; 90 | case "Blunt": blunt += 1; break; 91 | case "Pierce": pierce += 1; break; 92 | } 93 | } 94 | 95 | function attackCount(attackType : AttackType) { 96 | switch (attackType) { 97 | case "Slash": return slash; 98 | case "Blunt": return blunt; 99 | case "Pierce": return pierce 100 | default: return 0; 101 | } 102 | } 103 | 104 | return ( 105 |
106 |

EGO AFFINITIES:

107 |
108 | { SINS.map((sin) => 109 |
110 | {sin}/ 111 | {`x${egoResources.get(sin) ?? 0}`} 112 |
113 | )} 114 |
115 |
116 | { ATTACK_TYPES.map((attack) => 117 |
118 | 119 | {`x${attackCount(attack)}`} 120 |
121 | )} 122 |
123 |
124 | ) 125 | } -------------------------------------------------------------------------------- /components/SinnerCard.module.scss: -------------------------------------------------------------------------------- 1 | @use "vars"; 2 | @use "mixins"; 3 | @use "sass:math"; 4 | 5 | $profile-height: 90px; 6 | $skill-height: 36px; 7 | $passive-height: 28px; 8 | 9 | $item-border: 2px solid vars.$board-light; 10 | 11 | .container { 12 | position: relative; // as ref for absolutely positoned elements within 13 | 14 | background: vars.$page-bg; 15 | border: 2px solid vars.$board-light; 16 | border-radius: 10px; 17 | 18 | overflow: hidden; 19 | } 20 | .selected { 21 | border: 5px solid vars.$blood-red; 22 | } 23 | 24 | .top-container { 25 | @include mixins.hover-focus-highlight(true); 26 | position: relative; 27 | } 28 | .not-selected { 29 | &:not(:hover, :focus, :active) { 30 | .sinner-rarity, .skill-row, .sinner-img-container { 31 | @include mixins.gray-filter; 32 | } 33 | } 34 | } 35 | 36 | 37 | /********************************************* 38 | * Sinner Profile 39 | ********************************************/ 40 | 41 | .sinner-rarity { 42 | position: absolute; 43 | top: 2px; 44 | left: 2px; 45 | z-index: vars.$before-highlight-border-z - 1; 46 | height: clamp(30px, 2.5vw, 60px); 47 | } 48 | 49 | .checkbox { 50 | position: absolute; 51 | top: 5px; 52 | right: 5px; 53 | z-index: vars.$before-highlight-border-z + 1; 54 | 55 | width: 20%; 56 | aspect-ratio: 1; 57 | 58 | font-size: clamp(vars.pxToRem(55px), 4.2vw, vars.pxToRem(90px)); 59 | @media (max-width: vars.$mobile-screen) { 60 | font-size: 70px; 61 | } 62 | line-height: 0px; // Needed so aspect-ratio works. 63 | 64 | border: 2px solid vars.$board-light; 65 | border-radius: 4px; 66 | 67 | &:checked { 68 | border: 2px solid vars.$blood-red; 69 | } 70 | 71 | &:hover, &:focus { 72 | outline: none; 73 | border: 4px solid vars.$orange-highlight; 74 | &::after { 75 | content: "✘"; 76 | color: #{vars.$orange-highlight}80; 77 | } 78 | } 79 | } 80 | 81 | .sinner-img-container { 82 | position: relative; 83 | border-bottom: $item-border; 84 | } 85 | 86 | .sinner-img { 87 | display: block; 88 | width: 100%; 89 | aspect-ratio: vars.getSinnerCardAspectRatio($profile-height); 90 | 91 | object-position: center 15%; 92 | object-fit: cover; 93 | 94 | &:hover { 95 | cursor: pointer; 96 | } 97 | } 98 | 99 | .sinner-name { 100 | position: absolute; 101 | right: 0; 102 | bottom: 0; 103 | width: 100%; 104 | padding: 5% 1% 2%; 105 | 106 | background: linear-gradient( 107 | #FFFFFF00 0%, 108 | #{vars.$page-bg}BB 50%, 109 | #{vars.$page-bg} 110 | ); 111 | 112 | p { 113 | position: relative; 114 | left: 20%; 115 | width: 80%; 116 | 117 | color: vars.$text-yellow; 118 | font-size: vars.pxToRem(18px); 119 | font-weight: bold; 120 | text-align: right; 121 | 122 | overflow: hidden; 123 | text-overflow: ellipsis; 124 | white-space: nowrap; 125 | } 126 | } 127 | 128 | 129 | /********************************************* 130 | * Skills 131 | ********************************************/ 132 | 133 | .skill-row { 134 | display: flex; 135 | justify-content: stretch; 136 | width: 100%; 137 | aspect-ratio: vars.getSinnerCardAspectRatio($skill-height); 138 | 139 | font-size: vars.pxToRem(17px); 140 | } 141 | 142 | .skill-container { 143 | display: flex; 144 | align-items: center; 145 | justify-content: center; 146 | 147 | &:first-of-type { 148 | flex-grow: 3; 149 | margin-left: 5%; 150 | } 151 | &:nth-of-type(2) { 152 | flex-grow: 2; 153 | } 154 | &:nth-of-type(3) { 155 | flex-grow: 1; 156 | margin-right: 5%; 157 | } 158 | 159 | height: 100%; 160 | } 161 | 162 | .skill-container-icons { 163 | position: relative; // only as ref for absolutely positioned elems. 164 | height: 100%; 165 | 166 | display: flex; 167 | align-items: center; 168 | } 169 | 170 | .skill-affinity-icon { 171 | height: 80%; 172 | aspect-ratio: 1; 173 | z-index: 2; 174 | } 175 | .stack-1 { 176 | position: absolute; 177 | right: 25%; 178 | z-index: 1; 179 | } 180 | .stack-2 { 181 | position: absolute; 182 | right: 50%; 183 | z-index: 0; 184 | } 185 | 186 | .hex { 187 | height: 50%; 188 | position: absolute; 189 | top: 50%; 190 | right: -15%; 191 | z-index: 3; 192 | } 193 | 194 | /******************************************** 195 | * Passives 196 | *******************************************/ 197 | 198 | .passive-row { 199 | display: flex; 200 | width: 100%; 201 | aspect-ratio: vars.getSinnerCardAspectRatio($passive-height); 202 | } 203 | 204 | .passive-div { 205 | display: flex; 206 | align-items: center; 207 | flex-grow: 1; 208 | justify-content: center; 209 | 210 | font-size: vars.pxToRem(14px); 211 | 212 | border-top: $item-border; 213 | &:first-of-type { 214 | border-right: $item-border; 215 | } 216 | 217 | img { 218 | height: 80%; 219 | aspect-ratio: 1; 220 | } 221 | } 222 | 223 | .passive-insufficient { 224 | @include mixins.gray-filter; 225 | } -------------------------------------------------------------------------------- /components/IdentitySelection.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | @use 'mixins'; 3 | 4 | $id-card-width: vars.$sinner-card-width; 5 | $id-card-width-mobile: vars.$sinner-card-width*2/3; 6 | $id-card-height: 1.5*$id-card-width + 8px; 7 | $id-card-height-mobile: 1.5*$id-card-width-mobile + 4px; 8 | 9 | // Secret to allow scale transform without messing things up. 10 | // 4px to allow for 2deg rotation for mad style. 11 | $id-card-transform-factor: 1.1; 12 | $id-card-margin: $id-card-height*($id-card-transform-factor - 1)/2 + 4px; 13 | 14 | $id-costs-displacement: vars.pxToRem(30px); 15 | $id-card-border: 2px solid vars.$board-light; 16 | 17 | $button-margin: 2rem; 18 | $button-margin-mobile: 1rem; 19 | 20 | 21 | // The purpose of the separate board is just for the scrollbar 22 | // - So it is inside the rounded corners. 23 | .board { 24 | height: 100%; 25 | width: 100%; 26 | padding: 1rem; 27 | @media(max-width: vars.$mobile-screen) { 28 | padding: 0.5rem; 29 | } 30 | 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | gap: $button-margin; 35 | 36 | overflow: hidden; 37 | 38 | button { 39 | &:first-of-type { 40 | align-self: flex-end; 41 | } 42 | &:last-of-type { 43 | align-self: flex-start; 44 | } 45 | } 46 | } 47 | 48 | .container { 49 | @include mixins.orange-scrollbar; 50 | 51 | // Need max-h for scroll. 52 | max-height: calc(90vh - 2*vars.$button-h - 2*$button-margin); 53 | @media (max-width:vars.$mobile-screen) { 54 | max-height: calc(90vh - 2*vars.$button-h-mobile - 2*$button-margin-mobile); 55 | } 56 | width: 98%; 57 | @media (max-width: vars.$small-screen) { 58 | width: 94%; 59 | } 60 | padding-right: $id-costs-displacement + 0.1rem; 61 | 62 | display: grid; 63 | justify-items: center; 64 | justify-content: center; 65 | grid-template-columns: repeat(auto-fit, minmax($id-card-width + $id-card-margin/2, 1fr)); 66 | gap: 3rem; 67 | 68 | overflow-x: hidden; 69 | overflow-y: auto; 70 | } 71 | 72 | .id-container { 73 | position: relative; // ref for absolutely positioned kids. 74 | margin: $id-card-margin; 75 | 76 | &:not(:focus, :hover, .active) { 77 | .id-container-left, .id-container-right { 78 | @include mixins.gray-filter; 79 | } 80 | } 81 | 82 | &:hover, &:focus { 83 | cursor: pointer; 84 | outline: none; 85 | transform: scale($id-card-transform-factor) rotate(-2deg); 86 | 87 | .id-container-left { 88 | @include mixins.highlight-effect; 89 | } 90 | .id-container-right { 91 | border: 2px solid vars.$orange-highlight; 92 | } 93 | } 94 | 95 | @media (max-width: vars.$mobile-screen) { 96 | margin: 0; 97 | 98 | &:hover, &:focus { 99 | transform: none; 100 | } 101 | } 102 | } 103 | .active { 104 | .id-container-left, .id-container-right { 105 | filter: none; 106 | &::after { 107 | opacity: 0; 108 | } 109 | } 110 | } 111 | 112 | .id-container-left { 113 | position: relative; // ref for absolutely positioned kids. 114 | 115 | border-radius: 20px; 116 | border: $id-card-border; 117 | overflow: hidden; 118 | } 119 | 120 | .id-rarity { 121 | position: absolute; 122 | top: 4px; 123 | left: 4px; 124 | height: clamp(30px, 2vw, 45px); 125 | z-index: 1; 126 | } 127 | 128 | .id-image { 129 | display: block; 130 | width: $id-card-width; 131 | min-height: $id-card-height; 132 | @media(max-width: vars.$mobile-screen) { 133 | width: $id-card-width-mobile; 134 | min-height: 0; 135 | 136 | max-width: 100%; 137 | } 138 | 139 | object-fit: stretch; 140 | } 141 | 142 | .id-name { 143 | position: absolute; 144 | bottom: 0; 145 | z-index: 1; 146 | width: 100%; 147 | 148 | display: flex; 149 | justify-content: flex-end; 150 | 151 | background: linear-gradient( 152 | #FFFFFF00 0%, 153 | #{vars.$page-bg}BB 20%, 154 | #{vars.$page-bg} 155 | ); 156 | 157 | p { 158 | width: 85%; 159 | min-width: 150px; 160 | padding: vars.pxToRem(8px); 161 | 162 | color: vars.$text-yellow; 163 | font-size: vars.pxToRem(20px); 164 | font-weight: bold; 165 | text-align: right; 166 | 167 | @media(max-width: vars.$mobile-screen) { 168 | font-size: vars.pxToRem(16px); 169 | } 170 | } 171 | } 172 | 173 | .id-container-right { 174 | position: absolute; 175 | top: 1%; 176 | right: - $id-costs-displacement; 177 | 178 | background: vars.$page-bg; 179 | 180 | border-radius: 20px; 181 | border: $id-card-border; 182 | 183 | div { 184 | display: flex; 185 | align-items: center; 186 | gap: 0.1rem; 187 | 188 | width: 100%; 189 | padding: 0.5rem 0.5rem; 190 | } 191 | 192 | img { 193 | width: 38px; 194 | @media(max-width: vars.$mobile-screen) { 195 | width: 28px; 196 | } 197 | } 198 | 199 | p { 200 | font-size: vars.pxToRem(18px); 201 | font-weight: bold; 202 | @media(max-width: vars.$mobile-screen) { 203 | font-size: vars.pxToRem(14px); 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /components/EgoSelection.module.scss: -------------------------------------------------------------------------------- 1 | @use 'vars'; 2 | @use 'mixins'; 3 | 4 | $ego-card-width: vars.$sinner-card-width*1.5; 5 | $ego-card-width-mobile: vars.$sinner-card-width; 6 | $ego-card-height: $ego-card-width; 7 | $ego-card-height-mobile: $ego-card-width-mobile; 8 | 9 | // Secret to allow scale transform without messing things up. 10 | // 6px to allow for 2deg rotation for mad style. 11 | $ego-card-transform-factor: 1.1; 12 | $ego-card-margin: $ego-card-height*($ego-card-transform-factor - 1)/2 + 6px; 13 | 14 | $ego-card-border: 2px solid vars.$board-light; 15 | 16 | $button-h: vars.$button-h; 17 | $button-margin: 1rem; 18 | 19 | // The purpose of the separate board is just for the scrollbar 20 | // - So it is inside the rounded corners. 21 | .board { 22 | height: 100%; 23 | width: 100%; 24 | padding: 1rem; 25 | @media(max-width: vars.$mobile-screen) { 26 | padding: 0.5rem; 27 | } 28 | 29 | display: flex; 30 | flex-direction: column; 31 | align-items: center; 32 | gap: $button-margin; 33 | 34 | overflow: hidden; 35 | 36 | button { 37 | &:first-of-type { 38 | align-self: flex-end; 39 | } 40 | &:last-of-type { 41 | align-self: flex-start; 42 | } 43 | } 44 | } 45 | 46 | .container { 47 | @include mixins.orange-scrollbar; 48 | 49 | // Need max-h for scroll. 50 | max-height: calc(90vh - 2*vars.$button-h - 2*$button-margin); 51 | width: 98%; 52 | @media(max-width: vars.$small-screen) { 53 | width: 94%; 54 | } 55 | padding: 0 $ego-card-margin; 56 | 57 | display: grid; 58 | justify-items: center; 59 | justify-content: center; 60 | grid-template-columns: repeat(auto-fit, minmax($ego-card-width, 1fr)); 61 | gap: 3rem; 62 | 63 | overflow-x: hidden; 64 | overflow-y: auto; 65 | } 66 | 67 | .ego-container { 68 | margin: $ego-card-margin; 69 | display: flex; 70 | align-items: flex-start; 71 | } 72 | 73 | .ego-container-main { 74 | isolation: isolate; 75 | position: relative; // ref for absolutely positioned kids. 76 | 77 | &:not(.active) { 78 | .ego-image-container, .ego-rarity, .ego-name, .ego-affinity, .ego-costs { 79 | @include mixins.gray-filter; 80 | } 81 | } 82 | 83 | &:hover, &:focus { 84 | cursor: pointer; 85 | outline: none; 86 | transform: scale($ego-card-transform-factor) rotate(-2deg); 87 | 88 | .ego-image-container { 89 | @include mixins.highlight-effect; 90 | border-radius: 50%; 91 | &:after { 92 | border-radius: 50%; 93 | } 94 | } 95 | 96 | .ego-name, .ego-rarity, .ego-affinity { 97 | filter: none; 98 | } 99 | 100 | .ego-costs { 101 | border-color: vars.$orange-highlight; 102 | } 103 | } 104 | 105 | @media (max-width: vars.$mobile-screen) { 106 | margin: 0; 107 | &:hover, &:focus { 108 | transform: none; 109 | } 110 | } 111 | } 112 | .active { 113 | .ego-container-main { 114 | filter: none; 115 | &::after { 116 | opacity: 0; 117 | } 118 | } 119 | } 120 | 121 | .ego-image-container { 122 | width: $ego-card-width; 123 | min-height: $ego-card-height; 124 | @media(max-width: vars.$mobile-screen) { 125 | width: $ego-card-width-mobile; 126 | min-height: $ego-card-height-mobile; 127 | } 128 | 129 | background: linear-gradient( 130 | #{vars.$page-bg}, 131 | #FFFFFF00 30%, 132 | #{vars.$page-bg}10 70%, 133 | #{vars.$page-bg} 134 | ); 135 | 136 | isolation: isolate; 137 | overflow: hidden; 138 | } 139 | 140 | .ego-image { 141 | display: block; 142 | width: 100%; 143 | object-fit: fill; 144 | mix-blend-mode: overlay; 145 | } 146 | 147 | .ego-rarity { 148 | position: absolute; 149 | top: 27px; 150 | left: 35px; 151 | height: 25px; 152 | z-index: 1; 153 | 154 | transform: rotate(-20deg); 155 | } 156 | 157 | .ego-affinity { 158 | position: absolute; 159 | top: 35px; 160 | left: 12px; 161 | height: 35px; 162 | width: 35px; 163 | z-index: 1; 164 | 165 | transform: rotate(-20deg); 166 | } 167 | 168 | .ego-name { 169 | position: absolute; 170 | bottom: 5%;; 171 | width: 100%; 172 | max-width: $ego-card-width; 173 | 174 | color: vars.$text-yellow; 175 | font-weight: bold; 176 | font-size: vars.pxToRem(20px); 177 | line-height: vars.pxToRem(30px); 178 | text-align: center; 179 | 180 | white-space: nowrap; 181 | overflow: hidden; 182 | text-overflow: ellipsis; 183 | 184 | z-index: 1; 185 | } 186 | 187 | .ego-costs { 188 | position: absolute; 189 | top: 20px; 190 | right: 0px; 191 | max-height: $ego-card-height; 192 | 193 | display: flex; 194 | flex-direction: column; 195 | 196 | background: #{vars.$page-bg}CC; 197 | 198 | border-radius: 20px; 199 | border: $ego-card-border; 200 | 201 | transform: rotate(5deg); 202 | } 203 | 204 | .cost-and-text { 205 | display: flex; 206 | align-items: center; 207 | gap: 0.1rem; 208 | 209 | min-height: 0; // allow shirnking 210 | width: 100%; 211 | padding: 0.3rem; 212 | 213 | img { 214 | width: 38px; 215 | @media(max-width: vars.$mobile-screen) { 216 | width: 28px; 217 | } 218 | } 219 | 220 | p { 221 | font-size: vars.pxToRem(18px); 222 | font-weight: bold; 223 | @media(max-width: vars.$mobile-screen) { 224 | font-size: vars.pxToRem(14px); 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /components/SinnerCard.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import IdentitySelection from '@/components/IdentitySelection'; 3 | import SkillHexagon from '@/components/SkillHexagon'; 4 | import EgoComponent from '@/components/EgoComponent'; 5 | import { useTeamDispatchContext, useTeamResourcesContext, TeamDispatchFunctions } from '@/hooks/teamContext'; 6 | import { getRarityAsset, getSinTypeAsset} from '@/helpers/assets'; 7 | import { getSinnerIdSrcImg } from '@/helpers/sinnerData' 8 | import { passiveSufficient } from '@/helpers/costCalcs' 9 | import { TeamMember, IdentityData, EgoData, Skill, Passive, Sin, SinnerNumber } from '@/types/data'; 10 | import styles from './SinnerCard.module.scss'; 11 | 12 | export interface SinnerCardProps { 13 | member: TeamMember; 14 | idData: IdentityData[]; 15 | egoData: EgoData[]; 16 | } 17 | 18 | export default function SinnerCard( 19 | { 20 | member, 21 | idData, 22 | egoData, 23 | }: SinnerCardProps 24 | ) { 25 | const identity = member.id; 26 | 27 | const teamDispatch = useTeamDispatchContext(); 28 | const [setActive, _] = TeamDispatchFunctions(teamDispatch); 29 | 30 | const [showIdModal, setShowIdModal] = useState(false); 31 | 32 | function handleKeyDownChkBox(e: React.KeyboardEvent) { 33 | if (e.key === 'Enter') { 34 | e.preventDefault(); 35 | setActive(identity.sinner, !member.active); 36 | } 37 | } 38 | 39 | function handleKeyDownTop(e: React.KeyboardEvent) { 40 | if (e.key == 'Enter') { 41 | e.preventDefault(); 42 | setShowIdModal(!showIdModal); 43 | } 44 | } 45 | 46 | function sinnerProfile() { 47 | return ( 48 | <> 49 | {`${identity.rarity}-star 53 |
54 | {identity.name} 58 |
59 |

{identity.name}

60 |
61 |
62 | 63 | ) 64 | } 65 | 66 | return ( 67 |
68 | {/* Modals -- layout independent of rest of content. */} 69 | { showIdModal 70 | && 72 | } 73 |
e.preventDefault()} 75 | onClick={() => setShowIdModal(!showIdModal)} 76 | tabIndex={0} 77 | onKeyDown={handleKeyDownTop}> 78 | { sinnerProfile() } 79 | { skillRow(identity) } 80 | 81 |
82 | e.preventDefault()} 86 | onKeyDown={handleKeyDownChkBox} 87 | onChange={() => setActive(identity.sinner, !member.active)}/> 88 | 89 |
90 | ) 91 | } 92 | 93 | 94 | function skillRow(identity: IdentityData) { 95 | return ( 96 |
97 | { identity.skills.map((skill, index) => 98 | index < 3 && sinHexCombo(skill, index) 99 | )} 100 |
101 | ) 102 | } 103 | 104 | function sinHexCombo(skill: Skill, index: number) { 105 | return ( 106 |
107 |
108 | {skill.affinity}/ 111 | { index <= 1 112 | && {skill.affinity}/ 115 | } 116 | { index === 0 117 | && {skill.affinity}/ 120 | } 121 |
122 | 123 |
124 |
125 |
126 | ) 127 | } 128 | 129 | function PassiveRow({active, passive} : {active: Passive, passive: Passive}) { 130 | const resources = useTeamResourcesContext(); 131 | 132 | return ( 133 |
134 | { [active, passive].map((item, index) => 135 |
139 | {item.affinity}/ 140 | {`${item.activation.substring(0, 3)}\n x${item.cost}`} 141 |
142 | )} 143 |
144 | ) 145 | } 146 | -------------------------------------------------------------------------------- /hooks/teamContext.tsx: -------------------------------------------------------------------------------- 1 | import { useContext, createContext, useReducer } from 'react'; 2 | import initialIdData from './initialTeam.json'; 3 | import { TeamMember, IdentityData, EgoData, Sin, SINNER_NUMBERS, SinnerNumber } from '@/types/data'; 4 | 5 | type TeamEditAction = 6 | | {type: "set-active", sinner: SinnerNumber, active: boolean} 7 | | {type: "update-id", identity: IdentityData} 8 | | {type: "update-ego", ego: EgoData} 9 | | {type: "set-egos", egos: EgoData[]} 10 | 11 | const TeamContext = createContext([]); 12 | const TeamResourcesContext = createContext>(new Map()); 13 | const TeamDispatchContext = createContext>(initialDispatch); 14 | 15 | function TeamProvider({ 16 | children, 17 | initialState 18 | } : { 19 | children: React.ReactNode; 20 | initialState: TeamMember[]; 21 | }) { 22 | const [team, dispatchTeam] = useReducer(teamReducer, initialTeamMembers()); 23 | 24 | const teamResources = new Map(); 25 | for (const member of team) { 26 | if (!member.active) continue; 27 | member.id.skills.forEach((skill, index) => { 28 | const sin = skill.affinity; 29 | const resources = 3 - index; 30 | if (teamResources.has(sin)) { 31 | teamResources.set(sin, teamResources.get(sin)! + resources); 32 | } else { 33 | teamResources.set(sin, resources) 34 | } 35 | }) 36 | } 37 | 38 | return ( 39 | 40 | 41 | 42 | {children} 43 | 44 | 45 | 46 | ); 47 | } 48 | 49 | function useTeamContext() { 50 | return useContext(TeamContext); 51 | } 52 | 53 | function useTeamResourcesContext() { 54 | return useContext(TeamResourcesContext); 55 | } 56 | 57 | function useTeamDispatchContext() { 58 | return useContext(TeamDispatchContext); 59 | } 60 | 61 | 62 | function TeamDispatchFunctions(dispatchTeam : React.Dispatch) 63 | : [ 64 | (sinner: SinnerNumber, active: boolean) => void, 65 | (identity: IdentityData) => void 66 | ] 67 | { 68 | const setActive = (sinner: SinnerNumber, active: boolean) => { 69 | dispatchTeam({ 70 | type: "set-active", 71 | sinner: sinner, 72 | active: active, 73 | }); 74 | } 75 | const updateId = (identity: IdentityData) => { 76 | dispatchTeam({ 77 | type: "update-id", 78 | identity: identity, 79 | }); 80 | } 81 | return [setActive, updateId]; 82 | } 83 | 84 | function EgoDispatchFunctions(dispatchTeam: React.Dispatch) 85 | : [ 86 | (ego: EgoData) => void, 87 | (egos: EgoData[]) => void 88 | ] 89 | { 90 | const egoSelected = (ego: EgoData) => { 91 | dispatchTeam({ 92 | type: 'update-ego', 93 | ego: ego, 94 | }); 95 | } 96 | const setEgos = (egos: EgoData[]) => { 97 | dispatchTeam({ 98 | type: 'set-egos', 99 | egos: egos, 100 | }); 101 | } 102 | return [egoSelected, setEgos] 103 | } 104 | 105 | function teamReducer(team: TeamMember[], action: TeamEditAction) { 106 | switch(action.type) { 107 | case "set-active": { 108 | return team.map((member) => { 109 | return member.sinner === action.sinner ? {...member, active:action.active }: member; 110 | }) 111 | } 112 | case "update-id": { 113 | return team.map((member) => { 114 | return member.sinner === action.identity.sinner ? {...member, id: action.identity }: member; 115 | }) 116 | } 117 | case "update-ego": { 118 | const sinner = action.ego.sinner; 119 | const updatedMember = team.find((member) => member.sinner === sinner); 120 | if (!updatedMember) { 121 | console.error("Missing member for ego update!", sinner); 122 | return team; 123 | } 124 | 125 | const justRemove = updatedMember.egos.find((ego) => ego.name === action.ego.name) !== undefined; 126 | const newEgos = updatedMember.egos.filter((ego) => ego.rarity !== action.ego.rarity); 127 | if (!justRemove) { 128 | newEgos.push(action.ego); 129 | } 130 | 131 | return team.map((member) => { 132 | return member.sinner === action.ego.sinner ? {...member, egos:newEgos }: member; 133 | }) 134 | } 135 | case "set-egos": { 136 | const first = action.egos[0]; 137 | if (!first) return team; 138 | 139 | const sinner = first.sinner; 140 | const updatedMember = team.find((member) => member.sinner === sinner); 141 | if (!updatedMember) { 142 | console.error("Missing member for ego update!", sinner); 143 | return team; 144 | } 145 | 146 | return team.map((member) => { 147 | return member.sinner === first.sinner ? {...member, egos:action.egos }: member; 148 | }) 149 | } 150 | } 151 | } 152 | 153 | 154 | function initialTeamMembers() : TeamMember[] { 155 | const members = []; 156 | 157 | let index = 0; 158 | for (const identity of initialIdData) { 159 | const member = { 160 | sinner: SINNER_NUMBERS[index], 161 | id: identity as IdentityData, 162 | egos: [], 163 | active: index === 0, // Let Yi Sang be active to show how it works. 164 | } 165 | members.push(member); 166 | index++; 167 | } 168 | 169 | return members; 170 | } 171 | 172 | // Put here so ts doesn't complain and we don't have to deal with a null. 173 | function initialDispatch(action: TeamEditAction) { 174 | console.error(`Tried to call dispatch without TeamReducer setup!! \n 175 | Please ensure TeamProvider component is created before creating/doing any dispatch actions!\n 176 | Action tried ${action}`); 177 | } 178 | 179 | 180 | export { 181 | useTeamContext, useTeamDispatchContext, useTeamResourcesContext, 182 | TeamProvider, 183 | TeamDispatchFunctions, EgoDispatchFunctions, 184 | } -------------------------------------------------------------------------------- /hooks/initialTeam.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sinner": 1, 4 | "name": "LCB Sinner", 5 | "rarity": 1, 6 | "active": { 7 | "affinity": "Gloom", 8 | "cost": 4, 9 | "activation": "Res" 10 | }, 11 | "passive": { 12 | "affinity": "Gloom", 13 | "cost": 4, 14 | "activation": "Owned" 15 | }, 16 | "skills": [ 17 | { 18 | "affinity": "Gloom", 19 | "base": 3, 20 | "plus": 7, 21 | "coins": 1, 22 | "type": "Slash" 23 | }, 24 | { 25 | "affinity": "Envy", 26 | "base": 4, 27 | "plus": 4, 28 | "coins": 2, 29 | "type": "Pierce" 30 | }, 31 | { 32 | "affinity": "Sloth", 33 | "base": 6, 34 | "plus": 1, 35 | "coins": 3, 36 | "type": "Slash" 37 | }, 38 | { 39 | "affinity": "None", 40 | "base": 7, 41 | "plus": 3, 42 | "coins": 1, 43 | "type": "Guard" 44 | } 45 | ] 46 | }, 47 | { 48 | "sinner": 2, 49 | "name": "LCB Sinner", 50 | "rarity": 1, 51 | "active": { 52 | "affinity": "Pride", 53 | "cost": 2, 54 | "activation": "Res" 55 | }, 56 | "passive": { 57 | "affinity": "Pride", 58 | "cost": 3, 59 | "activation": "Owned" 60 | }, 61 | "skills": [ 62 | { 63 | "affinity": "Pride", 64 | "base": 3, 65 | "plus": 7, 66 | "coins": 1, 67 | "type": "Blunt" 68 | }, 69 | { 70 | "affinity": "Sloth", 71 | "base": 4, 72 | "plus": 4, 73 | "coins": 2, 74 | "type": "Blunt" 75 | }, 76 | { 77 | "affinity": "Gluttony", 78 | "base": 6, 79 | "plus": 2, 80 | "coins": 2, 81 | "type": "Pierce" 82 | }, 83 | { 84 | "affinity": "None", 85 | "base": 2, 86 | "plus": 10, 87 | "coins": 1, 88 | "type": "Dodge" 89 | } 90 | ] 91 | }, 92 | { 93 | "sinner": 3, 94 | "name": "LCB Sinner", 95 | "rarity": 1, 96 | "active": { 97 | "affinity": "Lust", 98 | "cost": 3, 99 | "activation": "Res" 100 | }, 101 | "passive": { 102 | "affinity": "Lust", 103 | "cost": 5, 104 | "activation": "Owned" 105 | }, 106 | "skills": [ 107 | { 108 | "affinity": "Lust", 109 | "base": 3, 110 | "plus": 7, 111 | "coins": 1, 112 | "type": "Pierce" 113 | }, 114 | { 115 | "affinity": "Envy", 116 | "base": 4, 117 | "plus": 10, 118 | "coins": 1, 119 | "type": "Pierce" 120 | }, 121 | { 122 | "affinity": "Gluttony", 123 | "base": 3, 124 | "plus": 3, 125 | "coins": 3, 126 | "type": "Pierce" 127 | }, 128 | { 129 | "affinity": "None", 130 | "base": 2, 131 | "plus": 10, 132 | "coins": 1, 133 | "type": "Dodge" 134 | } 135 | ] 136 | }, 137 | { 138 | "sinner": 4, 139 | "name": "LCB Sinner", 140 | "rarity": 1, 141 | "active": { 142 | "affinity": "Gluttony", 143 | "cost": 3, 144 | "activation": "Res" 145 | }, 146 | "passive": { 147 | "affinity": "Gluttony", 148 | "cost": 3, 149 | "activation": "Res" 150 | }, 151 | "skills": [ 152 | { 153 | "affinity": "Gluttony", 154 | "base": 3, 155 | "plus": 7, 156 | "coins": 1, 157 | "type": "Slash" 158 | }, 159 | { 160 | "affinity": "Lust", 161 | "base": 4, 162 | "plus": 4, 163 | "coins": 2, 164 | "type": "Slash" 165 | }, 166 | { 167 | "affinity": "Pride", 168 | "base": 5, 169 | "plus": 2, 170 | "coins": 3, 171 | "type": "Slash" 172 | }, 173 | { 174 | "affinity": "None", 175 | "base": 2, 176 | "plus": 10, 177 | "coins": 1, 178 | "type": "Dodge" 179 | } 180 | ] 181 | }, 182 | { 183 | "sinner": 5, 184 | "name": "LCB Sinner", 185 | "rarity": 1, 186 | "active": { 187 | "affinity": "Sloth", 188 | "cost": 2, 189 | "activation": "Owned" 190 | }, 191 | "passive": { 192 | "affinity": "Sloth", 193 | "cost": 3, 194 | "activation": "Owned" 195 | }, 196 | "skills": [ 197 | { 198 | "affinity": "Sloth", 199 | "base": 2, 200 | "plus": 4, 201 | "coins": 2, 202 | "type": "Blunt" 203 | }, 204 | { 205 | "affinity": "Pride", 206 | "base": 5, 207 | "plus": 8, 208 | "coins": 1, 209 | "type": "Blunt" 210 | }, 211 | { 212 | "affinity": "Gloom", 213 | "base": 4, 214 | "plus": 1, 215 | "coins": 4, 216 | "type": "Blunt" 217 | }, 218 | { 219 | "affinity": "None", 220 | "base": 8, 221 | "plus": 3, 222 | "coins": 1, 223 | "type": "Guard" 224 | } 225 | ] 226 | }, 227 | { 228 | "sinner": 6, 229 | "name": "LCB Sinner", 230 | "rarity": 1, 231 | "active": { 232 | "affinity": "Sloth", 233 | "cost": 2, 234 | "activation": "Res" 235 | }, 236 | "passive": { 237 | "affinity": "Sloth", 238 | "cost": 5, 239 | "activation": "Owned" 240 | }, 241 | "skills": [ 242 | { 243 | "affinity": "Pride", 244 | "base": 3, 245 | "plus": 7, 246 | "coins": 1, 247 | "type": "Blunt" 248 | }, 249 | { 250 | "affinity": "Sloth", 251 | "base": 4, 252 | "plus": 4, 253 | "coins": 2, 254 | "type": "Slash" 255 | }, 256 | { 257 | "affinity": "Lust", 258 | "base": 5, 259 | "plus": 4, 260 | "coins": 2, 261 | "type": "Blunt" 262 | }, 263 | { 264 | "affinity": "None", 265 | "base": 2, 266 | "plus": 10, 267 | "coins": 1, 268 | "type": "Dodge" 269 | } 270 | ] 271 | }, 272 | { 273 | "sinner": 7, 274 | "name": "LCB Sinner", 275 | "rarity": 1, 276 | "active": { 277 | "affinity": "Envy", 278 | "cost": 4, 279 | "activation": "Res" 280 | }, 281 | "passive": { 282 | "affinity": "Envy", 283 | "cost": 5, 284 | "activation": "Owned" 285 | }, 286 | "skills": [ 287 | { 288 | "affinity": "Envy", 289 | "base": 3, 290 | "plus": 7, 291 | "coins": 1, 292 | "type": "Blunt" 293 | }, 294 | { 295 | "affinity": "Wrath", 296 | "base": 4, 297 | "plus": 4, 298 | "coins": 2, 299 | "type": "Blunt" 300 | }, 301 | { 302 | "affinity": "Lust", 303 | "base": 4, 304 | "plus": 6, 305 | "coins": 2, 306 | "type": "Blunt" 307 | }, 308 | { 309 | "affinity": "Envy", 310 | "base": 7, 311 | "plus": 4, 312 | "coins": 1, 313 | "type": "Blunt" 314 | } 315 | ] 316 | }, 317 | { 318 | "sinner": 8, 319 | "name": "LCB Sinner", 320 | "rarity": 1, 321 | "active": { 322 | "affinity": "Wrath", 323 | "cost": 3, 324 | "activation": "Owned" 325 | }, 326 | "passive": { 327 | "affinity": "Wrath", 328 | "cost": 6, 329 | "activation": "Owned" 330 | }, 331 | "skills": [ 332 | { 333 | "affinity": "Wrath", 334 | "base": 3, 335 | "plus": 7, 336 | "coins": 1, 337 | "type": "Blunt" 338 | }, 339 | { 340 | "affinity": "Gluttony", 341 | "base": 5, 342 | "plus": 8, 343 | "coins": 1, 344 | "type": "Blunt" 345 | }, 346 | { 347 | "affinity": "Gloom", 348 | "base": 7, 349 | "plus": 12, 350 | "coins": 1, 351 | "type": "Blunt" 352 | }, 353 | { 354 | "affinity": "None", 355 | "base": 7, 356 | "plus": 3, 357 | "coins": 1, 358 | "type": "Guard" 359 | } 360 | ] 361 | }, 362 | { 363 | "sinner": 9, 364 | "name": "LCB Sinner", 365 | "rarity": 1, 366 | "active": { 367 | "affinity": "Wrath", 368 | "cost": 5, 369 | "activation": "Owned" 370 | }, 371 | "passive": { 372 | "affinity": "Wrath", 373 | "cost": 5, 374 | "activation": "Owned" 375 | }, 376 | "skills": [ 377 | { 378 | "affinity": "Gluttony", 379 | "base": 3, 380 | "plus": 7, 381 | "coins": 1, 382 | "type": "Slash" 383 | }, 384 | { 385 | "affinity": "Pride", 386 | "base": 4, 387 | "plus": 4, 388 | "coins": 2, 389 | "type": "Slash" 390 | }, 391 | { 392 | "affinity": "Wrath", 393 | "base": 2, 394 | "plus": 2, 395 | "coins": 4, 396 | "type": "Slash" 397 | }, 398 | { 399 | "affinity": "Wrath", 400 | "base": 7, 401 | "plus": 4, 402 | "coins": 1, 403 | "type": "Slash" 404 | } 405 | ] 406 | }, 407 | { 408 | "sinner": 11, 409 | "name": "LCB Sinner", 410 | "rarity": 1, 411 | "active": { 412 | "affinity": "Pride", 413 | "cost": 3, 414 | "activation": "Owned" 415 | }, 416 | "passive": { 417 | "affinity": "Pride", 418 | "cost": 3, 419 | "activation": "Owned" 420 | }, 421 | "skills": [ 422 | { 423 | "affinity": "Pride", 424 | "base": 3, 425 | "plus": 7, 426 | "coins": 1, 427 | "type": "Slash" 428 | }, 429 | { 430 | "affinity": "Wrath", 431 | "base": 4, 432 | "plus": 2, 433 | "coins": 3, 434 | "type": "Slash" 435 | }, 436 | { 437 | "affinity": "Envy", 438 | "base": 5, 439 | "plus": 2, 440 | "coins": 3, 441 | "type": "Slash" 442 | }, 443 | { 444 | "affinity": "Pride", 445 | "base": 7, 446 | "plus": 4, 447 | "coins": 1, 448 | "type": "Slash" 449 | } 450 | ] 451 | }, 452 | { 453 | "sinner": 12, 454 | "name": "LCB Sinner", 455 | "rarity": 1, 456 | "active": { 457 | "affinity": "Sloth", 458 | "cost": 4, 459 | "activation": "Owned" 460 | }, 461 | "passive": { 462 | "affinity": "Sloth", 463 | "cost": 5, 464 | "activation": "Owned" 465 | }, 466 | "skills": [ 467 | { 468 | "affinity": "Sloth", 469 | "base": 3, 470 | "plus": 2, 471 | "coins": 3, 472 | "type": "Pierce" 473 | }, 474 | { 475 | "affinity": "Pride", 476 | "base": 4, 477 | "plus": 4, 478 | "coins": 2, 479 | "type": "Slash" 480 | }, 481 | { 482 | "affinity": "Gloom", 483 | "base": 6, 484 | "plus": 14, 485 | "coins": 1, 486 | "type": "Pierce" 487 | }, 488 | { 489 | "affinity": "None", 490 | "base": 2, 491 | "plus": 10, 492 | "coins": 1, 493 | "type": "Dodge" 494 | } 495 | ] 496 | }, 497 | { 498 | "sinner": 13, 499 | "name": "LCB Sinner", 500 | "rarity": 1, 501 | "active": { 502 | "affinity": "Gloom", 503 | "cost": 3, 504 | "activation": "Owned" 505 | }, 506 | "passive": { 507 | "affinity": "Gloom", 508 | "cost": 3, 509 | "activation": "Owned" 510 | }, 511 | "skills": [ 512 | { 513 | "affinity": "Gloom", 514 | "base": 3, 515 | "plus": 7, 516 | "coins": 1, 517 | "type": "Slash" 518 | }, 519 | { 520 | "affinity": "Gluttony", 521 | "base": 4, 522 | "plus": 10, 523 | "coins": 1, 524 | "type": "Pierce" 525 | }, 526 | { 527 | "affinity": "Sloth", 528 | "base": 5, 529 | "plus": 4, 530 | "coins": 2, 531 | "type": "Pierce" 532 | }, 533 | { 534 | "affinity": "None", 535 | "base": 8, 536 | "plus": 2, 537 | "coins": 1, 538 | "type": "Guard" 539 | } 540 | ] 541 | } 542 | ] -------------------------------------------------------------------------------- /public/egos.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sinner": 1, 4 | "name": "Crow's Eye View", 5 | "filename": "crow_s eye view", 6 | "rarity": "ZAYIN", 7 | "affinity": "Sloth", 8 | "type": "Pierce", 9 | "costs": [ 10 | { 11 | "affinity": "Wrath", 12 | "cost": 1 13 | }, 14 | { 15 | "affinity": "Sloth", 16 | "cost": 3 17 | } 18 | ] 19 | }, 20 | { 21 | "sinner": 1, 22 | "name": "4th Match Flame", 23 | "rarity": "TETH", 24 | "affinity": "Wrath", 25 | "type": "Slash", 26 | "costs": [ 27 | { 28 | "affinity": "Wrath", 29 | "cost": 5 30 | }, 31 | { 32 | "affinity": "Sloth", 33 | "cost": 1 34 | }, 35 | { 36 | "affinity": "Gluttony", 37 | "cost": 1 38 | } 39 | ] 40 | }, 41 | { 42 | "sinner": 1, 43 | "name": "Wishing Cairn", 44 | "rarity": "TETH", 45 | "affinity": "Sloth", 46 | "type": "Pierce", 47 | "costs": [ 48 | { 49 | "affinity": "Gloom", 50 | "cost": 1 51 | }, 52 | { 53 | "affinity": "Sloth", 54 | "cost": 4 55 | } 56 | ] 57 | }, 58 | { 59 | "sinner": 1, 60 | "name": "Dimension Shredder", 61 | "rarity": "HE", 62 | "affinity": "Pride", 63 | "type": "Pierce", 64 | "costs": [ 65 | { 66 | "affinity": "Sloth", 67 | "cost": 3 68 | }, 69 | { 70 | "affinity": "Gluttony", 71 | "cost": 3 72 | } 73 | ] 74 | }, 75 | { 76 | "sinner": 1, 77 | "name": "Sunshower", 78 | "rarity": "WAW", 79 | "affinity": "Sloth", 80 | "type": "Pierce", 81 | "costs": [ 82 | { 83 | "affinity": "Sloth", 84 | "cost": 4 85 | }, 86 | { 87 | "affinity": "Gluttony", 88 | "cost": 2 89 | }, 90 | { 91 | "affinity": "Gloom", 92 | "cost": 2 93 | }, 94 | { 95 | "affinity": "Pride", 96 | "cost": 2 97 | } 98 | ] 99 | }, 100 | { 101 | "sinner": 2, 102 | "name": "Representation Emitter", 103 | "rarity": "ZAYIN", 104 | "affinity": "Pride", 105 | "type": "Blunt", 106 | "costs": [ 107 | { 108 | "affinity": "Gluttony", 109 | "cost": 2 110 | }, 111 | { 112 | "affinity": "Pride", 113 | "cost": 4 114 | } 115 | ] 116 | }, 117 | { 118 | "sinner": 2, 119 | "name": "Hex Nail", 120 | "rarity": "TETH", 121 | "affinity": "Envy", 122 | "type": "Pierce", 123 | "costs": [ 124 | { 125 | "affinity": "Envy", 126 | "cost": 6 127 | } 128 | ] 129 | }, 130 | { 131 | "sinner": 2, 132 | "name": "9:2", 133 | "filename": "9 2", 134 | "rarity": "TETH", 135 | "affinity": "Lust", 136 | "type": "Slash", 137 | "costs": [ 138 | { 139 | "affinity": "Lust", 140 | "cost": 1 141 | }, 142 | { 143 | "affinity": "Gluttony", 144 | "cost": 3 145 | }, 146 | { 147 | "affinity": "Pride", 148 | "cost": 1 149 | } 150 | ] 151 | }, 152 | { 153 | "sinner": 2, 154 | "name": "Fluid Sac", 155 | "rarity": "HE", 156 | "affinity": "Gloom", 157 | "type": "Blunt", 158 | "costs": [ 159 | { 160 | "affinity": "Lust", 161 | "cost": 2 162 | }, 163 | { 164 | "affinity": "Gloom", 165 | "cost": 4 166 | }, 167 | { 168 | "affinity": "Envy", 169 | "cost": 3 170 | } 171 | ] 172 | }, 173 | { 174 | "sinner": 2, 175 | "name": "Telepole", 176 | "rarity": "HE", 177 | "affinity": "Envy", 178 | "type": "Pierce", 179 | "costs": [ 180 | { 181 | "affinity": "Wrath", 182 | "cost": 1 183 | }, 184 | { 185 | "affinity": "Lust", 186 | "cost": 3 187 | }, 188 | { 189 | "affinity": "Envy", 190 | "cost": 3 191 | } 192 | ] 193 | }, 194 | { 195 | "sinner": 3, 196 | "name": "La Sangre de Sancho", 197 | "rarity": "ZAYIN", 198 | "affinity": "Lust", 199 | "type": "Pierce", 200 | "costs": [ 201 | { 202 | "affinity": "Lust", 203 | "cost": 2 204 | }, 205 | { 206 | "affinity": "Pride", 207 | "cost": 2 208 | } 209 | ] 210 | }, 211 | { 212 | "sinner": 3, 213 | "name": "Fluid Sac", 214 | "rarity": "HE", 215 | "affinity": "Gloom", 216 | "type": "Blunt", 217 | "costs": [ 218 | { 219 | "affinity": "Gloom", 220 | "cost": 4 221 | }, 222 | { 223 | "affinity": "Pride", 224 | "cost": 2 225 | }, 226 | { 227 | "affinity": "Lust", 228 | "cost": 1 229 | } 230 | ] 231 | }, 232 | { 233 | "sinner": 3, 234 | "name": "Telepole", 235 | "rarity": "HE", 236 | "affinity": "Envy", 237 | "type": "Pierce", 238 | "costs": [ 239 | { 240 | "affinity": "Wrath", 241 | "cost": 1 242 | }, 243 | { 244 | "affinity": "Gloom", 245 | "cost": 2 246 | }, 247 | { 248 | "affinity": "Envy", 249 | "cost": 2 250 | } 251 | ] 252 | }, 253 | { 254 | "sinner": 3, 255 | "name": "Lifetime Stew", 256 | "rarity": "TETH", 257 | "affinity": "Lust", 258 | "type": "Blunt", 259 | "costs": [ 260 | { 261 | "affinity": "Lust", 262 | "cost": 5 263 | } 264 | ] 265 | }, 266 | { 267 | "name": "Wishing Cairn ", 268 | "sinner": 3, 269 | "rarity": "TETH", 270 | "affinity": "Sloth", 271 | "type": "Blunt", 272 | "costs": [ 273 | { 274 | "affinity": "Wrath", 275 | "cost": "2" 276 | }, 277 | { 278 | "affinity": "Pride", 279 | "cost": "1" 280 | }, 281 | { 282 | "affinity": "Sloth", 283 | "cost": "2" 284 | } 285 | ] 286 | }, 287 | { 288 | "sinner": 4, 289 | "name": "Forest for the Flames", 290 | "rarity": "ZAYIN", 291 | "affinity": "Lust", 292 | "type": "Slash", 293 | "costs": [ 294 | { 295 | "affinity": "Wrath", 296 | "cost": 2 297 | }, 298 | { 299 | "affinity": "Lust", 300 | "cost": 2 301 | } 302 | ] 303 | }, 304 | { 305 | "sinner": 4, 306 | "name": "Soda", 307 | "rarity": "ZAYIN", 308 | "affinity": "Gloom", 309 | "type": "Pierce", 310 | "costs": [ 311 | { 312 | "affinity": "Gluttony", 313 | "cost": 2 314 | }, 315 | { 316 | "affinity": "Pride", 317 | "cost": 2 318 | }, 319 | { 320 | "affinity": "Envy", 321 | "cost": 2 322 | } 323 | ] 324 | }, 325 | { 326 | "sinner": 4, 327 | "name": "Red Eyes", 328 | "rarity": "TETH", 329 | "affinity": "Lust", 330 | "type": "Slash", 331 | "costs": [ 332 | { 333 | "affinity": "Lust", 334 | "cost": 2 335 | }, 336 | { 337 | "affinity": "Gluttony", 338 | "cost": 2 339 | }, 340 | { 341 | "affinity": "Envy", 342 | "cost": 3 343 | } 344 | ] 345 | }, 346 | { 347 | "sinner": 4, 348 | "name": "Blind Obsession", 349 | "rarity": "TETH", 350 | "affinity": "Pride", 351 | "type": "Slash", 352 | "costs": [ 353 | { 354 | "affinity": "Gloom", 355 | "cost": 2 356 | }, 357 | { 358 | "affinity": "Pride", 359 | "cost": 2 360 | }, 361 | { 362 | "affinity": "Envy", 363 | "cost": 2 364 | } 365 | ] 366 | }, 367 | { 368 | "sinner": 4, 369 | "name": "Red Eyes (Open)", 370 | "rarity": "HE", 371 | "affinity": "Envy", 372 | "type": "Slash", 373 | "costs": [ 374 | { 375 | "affinity": "Wrath", 376 | "cost": 2 377 | }, 378 | { 379 | "affinity": "Lust", 380 | "cost": 2 381 | }, 382 | { 383 | "affinity": "Envy", 384 | "cost": 3 385 | } 386 | ] 387 | }, 388 | { 389 | "sinner": 4, 390 | "name": "4th Match Flame", 391 | "rarity": "HE", 392 | "affinity": "Wrath", 393 | "type": "Slash", 394 | "costs": [ 395 | { 396 | "affinity": "Wrath", 397 | "cost": 4 398 | }, 399 | { 400 | "affinity": "Pride", 401 | "cost": 2 402 | } 403 | ] 404 | }, 405 | { 406 | "sinner": 5, 407 | "name": "Chains of Others", 408 | "rarity": "ZAYIN", 409 | "affinity": "Pride", 410 | "type": "Blunt", 411 | "costs": [ 412 | { 413 | "affinity": "Sloth", 414 | "cost": 1 415 | }, 416 | { 417 | "affinity": "Gloom", 418 | "cost": 1 419 | }, 420 | { 421 | "affinity": "Envy", 422 | "cost": 2 423 | } 424 | ] 425 | }, 426 | { 427 | "sinner": 5, 428 | "name": "You Want To Get Beat? Hurtily?", 429 | "filename": "you want to get beat hurtily", 430 | "rarity": "TETH", 431 | "affinity": "Envy", 432 | "type": "Blunt", 433 | "costs": [ 434 | { 435 | "affinity": "Sloth", 436 | "cost": 2 437 | }, 438 | { 439 | "affinity": "Pride", 440 | "cost": 1 441 | }, 442 | { 443 | "affinity": "Envy", 444 | "cost": 2 445 | } 446 | ] 447 | }, 448 | { 449 | "sinner": 5, 450 | "name": "Pursuance", 451 | "rarity": "HE", 452 | "affinity": "Sloth", 453 | "type": "Blunt", 454 | "costs": [ 455 | { 456 | "affinity": "Sloth", 457 | "cost": 4 458 | }, 459 | { 460 | "affinity": "Gloom", 461 | "cost": 1 462 | }, 463 | { 464 | "affinity": "Pride", 465 | "cost": 2 466 | } 467 | ] 468 | }, 469 | { 470 | "sinner": 5, 471 | "name": "Capote", 472 | "rarity": "HE", 473 | "affinity": "Wrath", 474 | "type": "Blunt", 475 | "costs": [ 476 | { 477 | "affinity": "Wrath", 478 | "cost": 2 479 | }, 480 | { 481 | "affinity": "Lust", 482 | "cost": 1 483 | }, 484 | { 485 | "affinity": "Sloth", 486 | "cost": 2 487 | } 488 | ] 489 | }, 490 | { 491 | "name": "Regret", 492 | "sinner": 5, 493 | "affinity": "Wrath", 494 | "rarity": "TETH", 495 | "type": "Blunt", 496 | "costs": [ 497 | { 498 | "affinity": "Wrath", 499 | "cost": "3" 500 | }, 501 | { 502 | "affinity": "Pride", 503 | "cost": "2" 504 | } 505 | ] 506 | }, 507 | { 508 | "sinner": 6, 509 | "name": "Land of Illusion", 510 | "rarity": "ZAYIN", 511 | "affinity": "Gloom", 512 | "type": "Blunt", 513 | "costs": [ 514 | { 515 | "affinity": "Lust", 516 | "cost": 1 517 | }, 518 | { 519 | "affinity": "Gloom", 520 | "cost": 5 521 | } 522 | ] 523 | }, 524 | { 525 | "sinner": 6, 526 | "name": "Roseate Desire", 527 | "rarity": "TETH", 528 | "affinity": "Lust", 529 | "type": "Pierce", 530 | "costs": [ 531 | { 532 | "affinity": "Lust", 533 | "cost": 4 534 | }, 535 | { 536 | "affinity": "Envy", 537 | "cost": 2 538 | } 539 | ] 540 | }, 541 | { 542 | "sinner": 6, 543 | "name": "Soda", 544 | "rarity": "TETH", 545 | "affinity": "Envy", 546 | "type": "Blunt", 547 | "costs": [ 548 | { 549 | "affinity": "Gloom", 550 | "cost": 3 551 | }, 552 | { 553 | "affinity": "Gluttony", 554 | "cost": 2 555 | }, 556 | { 557 | "affinity": "Envy", 558 | "cost": 1 559 | } 560 | ] 561 | }, 562 | { 563 | "sinner": 6, 564 | "name": "Dimension Shredder", 565 | "rarity": "HE", 566 | "affinity": "Pride", 567 | "type": "Slash", 568 | "costs": [ 569 | { 570 | "affinity": "Gluttony", 571 | "cost": 3 572 | }, 573 | { 574 | "affinity": "Pride", 575 | "cost": 3 576 | } 577 | ] 578 | }, 579 | { 580 | "sinner": 6, 581 | "name": "Effervescent Corrosion", 582 | "rarity": "HE", 583 | "affinity": "Gluttony", 584 | "type": "Pierce", 585 | "costs": [ 586 | { 587 | "affinity": "Gluttony", 588 | "cost": 6 589 | }, 590 | { 591 | "affinity": "Gloom", 592 | "cost": 1 593 | } 594 | ] 595 | }, 596 | { 597 | "sinner": 7, 598 | "name": "Bodysack", 599 | "rarity": "ZAYIN", 600 | "affinity": "Envy", 601 | "type": "Blunt", 602 | "costs": [ 603 | { 604 | "affinity": "Lust", 605 | "cost": 2 606 | }, 607 | { 608 | "affinity": "Envy", 609 | "cost": 2 610 | } 611 | ] 612 | }, 613 | { 614 | "sinner": 7, 615 | "name": "AEDD", 616 | "rarity": "TETH", 617 | "affinity": "Gloom", 618 | "type": "Blunt", 619 | "costs": [ 620 | { 621 | "affinity": "Gloom", 622 | "cost": 3 623 | }, 624 | { 625 | "affinity": "Envy", 626 | "cost": 2 627 | } 628 | ] 629 | }, 630 | { 631 | "sinner": 7, 632 | "name": "Holiday", 633 | "rarity": "TETH", 634 | "affinity": "Gluttony", 635 | "type": "Blunt", 636 | "costs": [ 637 | { 638 | "affinity": "Gluttony", 639 | "cost": 3 640 | }, 641 | { 642 | "affinity": "Envy", 643 | "cost": 2 644 | } 645 | ] 646 | }, 647 | { 648 | "sinner": 7, 649 | "name": "Telepole", 650 | "rarity": "HE", 651 | "affinity": "Envy", 652 | "type": "Pierce", 653 | "costs": [ 654 | { 655 | "affinity": "Wrath", 656 | "cost": 3 657 | }, 658 | { 659 | "affinity": "Lust", 660 | "cost": 2 661 | }, 662 | { 663 | "affinity": "Envy", 664 | "cost": 3 665 | } 666 | ] 667 | }, 668 | { 669 | "name": "Ya Śūnyatā Tad Rūpam", 670 | "affinity": "Lust", 671 | "sinner": 7, 672 | "rarity": "HE", 673 | "type": "Blunt", 674 | "costs": [ 675 | { 676 | "affinity": "Wrath", 677 | "cost": "2" 678 | }, 679 | { 680 | "affinity": "Lust", 681 | "cost": "2" 682 | }, 683 | { 684 | "affinity": "Sloth", 685 | "cost": "2" 686 | }, 687 | { 688 | "affinity": "Gloom", 689 | "cost": "2" 690 | } 691 | ] 692 | }, 693 | { 694 | "sinner": 8, 695 | "name": "Snagharpoon", 696 | "rarity": "ZAYIN", 697 | "affinity": "Gloom", 698 | "type": "Blunt", 699 | "costs": [ 700 | { 701 | "affinity": "Wrath", 702 | "cost": 2 703 | }, 704 | { 705 | "affinity": "Gloom", 706 | "cost": 2 707 | } 708 | ] 709 | }, 710 | { 711 | "sinner": 8, 712 | "name": "Roseate Desire", 713 | "rarity": "TETH", 714 | "affinity": "Lust", 715 | "type": "Pierce", 716 | "costs": [ 717 | { 718 | "affinity": "Wrath", 719 | "cost": 1 720 | }, 721 | { 722 | "affinity": "Lust", 723 | "cost": 4 724 | } 725 | ] 726 | }, 727 | { 728 | "sinner": 8, 729 | "name": "Capote", 730 | "rarity": "TETH", 731 | "affinity": "Wrath", 732 | "type": "Blunt", 733 | "costs": [ 734 | { 735 | "affinity": "Wrath", 736 | "cost": 2 737 | }, 738 | { 739 | "affinity": "Lust", 740 | "cost": 2 741 | }, 742 | { 743 | "affinity": "Sloth", 744 | "cost": 1 745 | } 746 | ] 747 | }, 748 | { 749 | "sinner": 8, 750 | "name": "Ardor Blossom Star", 751 | "rarity": "HE", 752 | "affinity": "Wrath", 753 | "type": "Pierce", 754 | "costs": [ 755 | { 756 | "affinity": "Wrath", 757 | "cost": 4 758 | }, 759 | { 760 | "affinity": "Lust", 761 | "cost": 2 762 | }, 763 | { 764 | "affinity": "Envy", 765 | "cost": 1 766 | } 767 | ] 768 | }, 769 | { 770 | "sinner": 8, 771 | "name": "Blind Obsession", 772 | "rarity": "WAW", 773 | "affinity": "Pride", 774 | "type": "Pierce", 775 | "costs": [ 776 | { 777 | "affinity": "Wrath", 778 | "cost": 2 779 | }, 780 | { 781 | "affinity": "Gloom", 782 | "cost": 3 783 | }, 784 | { 785 | "affinity": "Pride", 786 | "cost": 3 787 | }, 788 | { 789 | "affinity": "Envy", 790 | "cost": 3 791 | } 792 | ] 793 | }, 794 | { 795 | "sinner": 9, 796 | "name": "What is Cast", 797 | "rarity": "ZAYIN", 798 | "affinity": "Pride", 799 | "type": "Slash", 800 | "costs": [ 801 | { 802 | "affinity": "Gloom", 803 | "cost": 1 804 | }, 805 | { 806 | "affinity": "Pride", 807 | "cost": 3 808 | } 809 | ] 810 | }, 811 | { 812 | "sinner": 9, 813 | "name": "Rime Shank", 814 | "rarity": "TETH", 815 | "affinity": "Gloom", 816 | "type": "Blunt", 817 | "costs": [ 818 | { 819 | "affinity": "Gloom", 820 | "cost": 5 821 | }, 822 | { 823 | "affinity": "Envy", 824 | "cost": 3 825 | } 826 | ] 827 | }, 828 | { 829 | "sinner": 9, 830 | "name": "Effervescent Corrosion", 831 | "rarity": "TETH", 832 | "affinity": "Gluttony", 833 | "type": "Blunt", 834 | "costs": [ 835 | { 836 | "affinity": "Sloth", 837 | "cost": 2 838 | }, 839 | { 840 | "affinity": "Gloom", 841 | "cost": 2 842 | }, 843 | { 844 | "affinity": "Pride", 845 | "cost": 2 846 | } 847 | ] 848 | }, 849 | { 850 | "sinner": 9, 851 | "name": "4th Match Flame", 852 | "rarity": "HE", 853 | "affinity": "Wrath", 854 | "type": "Slash", 855 | "costs": [ 856 | { 857 | "affinity": "Wrath", 858 | "cost": 3 859 | }, 860 | { 861 | "affinity": "Pride", 862 | "cost": 2 863 | }, 864 | { 865 | "affinity": "Envy", 866 | "cost": 1 867 | } 868 | ] 869 | }, 870 | { 871 | "sinner": 9, 872 | "name": "Pursuance", 873 | "rarity": "HE", 874 | "affinity": "Sloth", 875 | "type": "Slash", 876 | "costs": [ 877 | { 878 | "affinity": "Sloth", 879 | "cost": 4 880 | }, 881 | { 882 | "affinity": "Pride", 883 | "cost": 3 884 | } 885 | ] 886 | }, 887 | { 888 | "sinner": 11, 889 | "name": "Branch of Knowledge", 890 | "rarity": "ZAYIN", 891 | "affinity": "Gluttony", 892 | "type": "Slash", 893 | "costs": [ 894 | { 895 | "affinity": "Wrath", 896 | "cost": 1 897 | }, 898 | { 899 | "affinity": "Gluttony", 900 | "cost": 3 901 | } 902 | ] 903 | }, 904 | { 905 | "sinner": 11, 906 | "name": "Impending Day", 907 | "rarity": "TETH", 908 | "affinity": "Wrath", 909 | "type": "Blunt", 910 | "costs": [ 911 | { 912 | "affinity": "Wrath", 913 | "cost": 3 914 | }, 915 | { 916 | "affinity": "Lust", 917 | "cost": 2 918 | } 919 | ] 920 | }, 921 | { 922 | "sinner": 11, 923 | "name": "Lifetime Stew", 924 | "rarity": "TETH", 925 | "affinity": "Lust", 926 | "type": "Blunt", 927 | "costs": [ 928 | { 929 | "affinity": "Wrath", 930 | "cost": 3 931 | }, 932 | { 933 | "affinity": "Lust", 934 | "cost": 2 935 | }, 936 | { 937 | "affinity": "Gluttony", 938 | "cost": 1 939 | } 940 | ] 941 | }, 942 | { 943 | "sinner": 11, 944 | "name": "Lantern", 945 | "rarity": "HE", 946 | "affinity": "Gluttony", 947 | "type": "Slash", 948 | "costs": [ 949 | { 950 | "affinity": "Lust", 951 | "cost": 1 952 | }, 953 | { 954 | "affinity": "Gluttony", 955 | "cost": 4 956 | }, 957 | { 958 | "affinity": "Pride", 959 | "cost": 2 960 | } 961 | ] 962 | }, 963 | { 964 | "sinner": 11, 965 | "name": "9:2", 966 | "filename": "9 2", 967 | "rarity": "HE", 968 | "affinity": "Lust", 969 | "type": "Blunt", 970 | "costs": [ 971 | { 972 | "affinity": "Wrath", 973 | "cost": 2 974 | }, 975 | { 976 | "affinity": "Lust", 977 | "cost": 5 978 | }, 979 | { 980 | "affinity": "Envy", 981 | "cost": 1 982 | } 983 | ] 984 | }, 985 | { 986 | "sinner": 12, 987 | "name": "To Páthos Máthos", 988 | "rarity": "ZAYIN", 989 | "affinity": "Pride", 990 | "type": "Pierce", 991 | "costs": [ 992 | { 993 | "affinity": "Sloth", 994 | "cost": 2 995 | }, 996 | { 997 | "affinity": "Pride", 998 | "cost": 2 999 | } 1000 | ] 1001 | }, 1002 | { 1003 | "sinner": 12, 1004 | "name": "Ya Śūnyatā Tad Rūpam", 1005 | "rarity": "TETH", 1006 | "affinity": "Lust", 1007 | "type": "Slash", 1008 | "costs": [ 1009 | { 1010 | "affinity": "Lust", 1011 | "cost": 2 1012 | }, 1013 | { 1014 | "affinity": "Sloth", 1015 | "cost": 2 1016 | }, 1017 | { 1018 | "affinity": "Pride", 1019 | "cost": 2 1020 | } 1021 | ] 1022 | }, 1023 | { 1024 | "sinner": 12, 1025 | "name": "Sunshower", 1026 | "rarity": "TETH", 1027 | "affinity": "Gluttony", 1028 | "type": "Pierce", 1029 | "costs": [ 1030 | { 1031 | "affinity": "Sloth", 1032 | "cost": 2 1033 | }, 1034 | { 1035 | "affinity": "Gluttony", 1036 | "cost": 2 1037 | }, 1038 | { 1039 | "affinity": "Gloom", 1040 | "cost": 1 1041 | } 1042 | ] 1043 | }, 1044 | { 1045 | "sinner": 12, 1046 | "name": "Ebony Stem", 1047 | "rarity": "HE", 1048 | "affinity": "Gluttony", 1049 | "type": "Pierce", 1050 | "costs": [ 1051 | { 1052 | "affinity": "Lust", 1053 | "cost": 2 1054 | }, 1055 | { 1056 | "affinity": "Gluttony", 1057 | "cost": 3 1058 | }, 1059 | { 1060 | "affinity": "Gloom", 1061 | "cost": 1 1062 | }, 1063 | { 1064 | "affinity": "Pride", 1065 | "cost": 4 1066 | } 1067 | ] 1068 | }, 1069 | { 1070 | "sinner": 12, 1071 | "name": "Holiday", 1072 | "rarity": "HE", 1073 | "affinity": "Wrath", 1074 | "type": "Blunt", 1075 | "costs": [ 1076 | { 1077 | "affinity": "Lust", 1078 | "cost": 2 1079 | }, 1080 | { 1081 | "affinity": "Sloth", 1082 | "cost": 1 1083 | }, 1084 | { 1085 | "affinity": "Pride", 1086 | "cost": 3 1087 | }, 1088 | { 1089 | "affinity": "Envy", 1090 | "cost": 2 1091 | } 1092 | ] 1093 | }, 1094 | { 1095 | "sinner": 13, 1096 | "name": "Legerdemain", 1097 | "rarity": "ZAYIN", 1098 | "affinity": "Gluttony", 1099 | "type": "Blunt", 1100 | "costs": [ 1101 | { 1102 | "affinity": "Sloth", 1103 | "cost": 1 1104 | }, 1105 | { 1106 | "affinity": "Gluttony", 1107 | "cost": 3 1108 | } 1109 | ] 1110 | }, 1111 | { 1112 | "sinner": 13, 1113 | "name": "Suddenly, One Day", 1114 | "rarity": "ZAYIN", 1115 | "affinity": "Sloth", 1116 | "type": "Blunt", 1117 | "costs": [ 1118 | { 1119 | "affinity": "Lust", 1120 | "cost": 3 1121 | }, 1122 | { 1123 | "affinity": "Gloom", 1124 | "cost": 1 1125 | } 1126 | ] 1127 | }, 1128 | { 1129 | "sinner": 13, 1130 | "name": "Lantern", 1131 | "rarity": "TETH", 1132 | "affinity": "Gluttony", 1133 | "type": "Pierce", 1134 | "costs": [ 1135 | { 1136 | "affinity": "Sloth", 1137 | "cost": 1 1138 | }, 1139 | { 1140 | "affinity": "Gluttony", 1141 | "cost": 4 1142 | } 1143 | ] 1144 | }, 1145 | { 1146 | "sinner": 13, 1147 | "name": "AEDD", 1148 | "rarity": "HE", 1149 | "affinity": "Gloom", 1150 | "type": "Blunt", 1151 | "costs": [ 1152 | { 1153 | "affinity": "Gloom", 1154 | "cost": 3 1155 | }, 1156 | { 1157 | "affinity": "Envy", 1158 | "cost": 3 1159 | } 1160 | ] 1161 | }, 1162 | { 1163 | "name": "Garden of Thorns ", 1164 | "sinner": 13, 1165 | "rarity": "WAW", 1166 | "affinity": "Lust", 1167 | "type": "Slash", 1168 | "costs": [ 1169 | { 1170 | "affinity": "Wrath", 1171 | "cost": "2" 1172 | }, 1173 | { 1174 | "affinity": "Lust", 1175 | "cost": "2" 1176 | }, 1177 | { 1178 | "affinity": "Sloth", 1179 | "cost": "2" 1180 | }, 1181 | { 1182 | "affinity": "Gluttony", 1183 | "cost": "2" 1184 | } 1185 | ] 1186 | } 1187 | ] 1188 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------