Initial Commit

Signed-off-by: Avior <florian.bouillon@delta-wings.net>
This commit is contained in:
Florian Bouillon 2021-03-14 02:07:52 +01:00
commit f47ab40ffd
Signed by: Florian Bouillon
GPG Key ID: 50BD648F12C86AB6
83 changed files with 8420 additions and 0 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
root = true
[*]
indent_style = tab
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_style = space
indent_size = 2
trim_trailing_whitespace = false

8
.eslintignore Normal file
View File

@ -0,0 +1,8 @@
node_modules
out
.next
next-env.d.ts
*.js
__tests__

191
.eslintrc.js Normal file
View File

@ -0,0 +1,191 @@
module.exports = {
env: {
browser: true,
es6: true,
node: true
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended"
],
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly"
},
parser: "@typescript-eslint/parser",
parserOptions: {
project: "tsconfig.json",
ecmaFeatures: {
jsx: true
},
ecmaVersion: 2018,
sourceType: "module"
},
settings: {
react: {
version: "detect"
}
},
plugins: [
"react",
"@typescript-eslint"
],
rules: {
indent: [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
quotes: "off",
"@typescript-eslint/quotes": [
"error",
"single",
{ avoidEscape: true }
],
semi: "off",
"@typescript-eslint/semi": [
"error",
"never"
],
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": ["error", { "allowTernary": true }],
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": [
"error",
{
default: 'generic'
}
],
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/ban-types": "error",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
accessibility: "explicit"
}
],
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/member-delimiter-style": [
"error",
{
multiline: {
delimiter: "none",
requireLast: true
},
singleline: {
delimiter: "comma",
requireLast: false
}
}
],
"@typescript-eslint/member-ordering": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-parameter-properties": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
"arrow-body-style": "error",
"arrow-parens": [
"error",
"always"
],
complexity: "off",
"constructor-super": "error",
curly: "error",
"dot-notation": "error",
"eol-last": "error",
eqeqeq: [
"error",
"smart"
],
"guard-for-in": "error",
"id-blacklist": [
"error",
"any",
"Number",
"number",
"String",
"string",
"Boolean",
"boolean",
"Undefined"
],
"id-match": "error",
"max-classes-per-file": [
"error",
1
],
"max-len": [
"warn",
{
code: 120
}
],
"new-parens": "error",
"no-bitwise": "error",
"no-caller": "error",
"no-cond-assign": "error",
"no-debugger": "error",
"no-empty": "error",
"no-eval": "error",
"no-fallthrough": "off",
"no-invalid-this": "off",
"no-multiple-empty-lines": "error",
"no-new-wrappers": "error",
"no-shadow": [
"error",
{
hoist: "all"
}
],
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-underscore-dangle": "error",
"no-unsafe-finally": "error",
"no-unused-labels": "error",
"no-unused-vars": "off",
"no-var": "error",
"object-shorthand": "error",
"one-var": [
"error",
"never"
],
"prefer-const": "error",
"quote-props": [
"error",
"consistent-as-needed"
],
"radix": "error",
"space-before-function-paren": "off",
"@typescript-eslint/space-before-function-paren": ["error", {
asyncArrow: "always",
anonymous: "never",
named: "never"
}],
"spaced-comment": "error",
"use-isnan": "error",
"valid-typeof": "off",
}
};

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

27
.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
.env*
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
dist/

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib"
}

1
README.md Normal file
View File

@ -0,0 +1 @@
# Avior Games

2
next-env.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />

22
next.config.js Normal file
View File

@ -0,0 +1,22 @@
const stylus = require('@zeit/next-stylus')
const css = require('@zeit/next-css')
const withPlugins = require('next-compose-plugins')
const {PHASE_DEVELOPMENT_SERVER} = require('next/constants')
module.exports = withPlugins([
[stylus, {
cssModules: true,
cssLoaderOptions: {
localIdentName: "[hash:base64:6]",
},
[PHASE_DEVELOPMENT_SERVER]: {
cssLoaderOptions: {
localIdentName: "[path][name]__[local]"
}
}
}],
[css, {
cssModules: false
}]
]
)

40
package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "@dzeio/url-shortener",
"version": "1.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"server": "next start",
"lint": "eslint . --ext .ts,.tsx",
"test": "jest --config jext.config.js"
},
"dependencies": {
"@dzeio/components": "^0.2.1",
"@zeit/next-css": "^1.0.1",
"@zeit/next-stylus": "^1.0.1",
"easy-sitemap": "^1.0.0",
"next": "^10.0.3",
"next-compose-plugins": "^2.2.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-feather": "^2.0.9",
"stylus": "^0.54.7",
"typescript": "^4.1.3",
"webpack": "^4.46.0"
},
"devDependencies": {
"@babel/core": "^7.8.7",
"@types/favicons": "^6.2.0",
"@types/node": "^14.0.0",
"@types/react": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^4.14.1",
"@typescript-eslint/parser": "^4.14.1",
"babel-preset-react-app": "^10.0.0",
"eslint": "^7.1.0",
"eslint-plugin-react": "^7.18.3",
"favicons": "^6.2.0",
"ts-node": "^9.1.1",
"vercel": "^21.2.2"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

4
src/client/styl/stylus.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module '*.styl' {
const content: any
export = content
}

13
src/pages/_app.tsx Normal file
View File

@ -0,0 +1,13 @@
import React from 'react'
import App from 'next/app'
import '@dzeio/components/style.css'
export default class CApp extends App {
public render() {
const { Component, pageProps } = this.props
return(<Component {...pageProps} />)
}
}

19
src/pages/_document.tsx Normal file
View File

@ -0,0 +1,19 @@
import React from 'react'
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
public render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument

13
src/pages/index.tsx Normal file
View File

@ -0,0 +1,13 @@
import { Link, Text } from '@dzeio/components'
import React from 'react'
export default class Index extends React.Component {
public render = () => (
<main>
<Text>
<Link href="/pokemon-shuffle">Pokémon Shuffle</Link>
</Text>
</main>
)
}

View File

@ -0,0 +1,292 @@
import { Button, Table, Text, Util } from '@dzeio/components'
import React from 'react'
import css from './pokemon-shuffle.styl'
interface Cell {
id: number
horizontalCombo?: true
verticalCombo?: true
justSpawned?: true
isFalling?: true
}
interface States {
items: Array<Array<Cell | undefined>>
loading?: true
movingItem?: {x: number, y: number, cell: Cell}
points: number
turn: number
combo: number
comboMax: number
cursorPos: {x: number, y: number}
}
const ITEM_COUNT = 4
const BOARD_SIZE = 6
let n = BOARD_SIZE
export default class PokemonShuffle extends React.Component<unknown, States> {
public state: States = {
items: [[]],
points: 0,
turn: 0,
combo: 0,
comboMax: 0,
cursorPos: {x: 0, y: 0}
}
public render = () => (
<main>
<ul>
<li><Text>Tour: {this.state.turn}</Text></li>
<li><Text>Combo: {this.state.combo}, Max: {this.state.comboMax}</Text></li>
<li><Text>Points: {this.state.points}</Text></li>
</ul>
<Table >
<tbody className={`${css.table} ${this.state.loading ? css.loading : ''}`}>
{this.state.items.map((row, y) => (
<tr key={y}>
{row.map((cell, x) => (
<td
key={cell?.isFalling ? n++ : x}
onClick={this.onCellClick(x, y)}
className={css.cellParent}
>
{cell && (
<Text className={Util.buildClassName(
css[`icon-${cell.id}`],
css.cell,
[css.isFalling, cell.isFalling],
[css.justSpawned, cell.justSpawned],
[css.explode, cell.horizontalCombo || cell.verticalCombo]
)}>
<div></div>
</Text>
)}
</td>
))}
</tr>
))}
</tbody>
</Table>
<Button onClick={() => this.calculate()}>Calculate!</Button>
<Button onClick={() => this.start()}>Start!</Button>
{/* <Input block type="textarea" value={JSON.stringify(this.state.items)}/> */}
{this.state.movingItem && (
<div style={{
position: 'absolute',
left: this.state.cursorPos.x,
top: this.state.cursorPos.y,
transform: 'translate(-50%, -50%)',
pointerEvents: 'none'
}}>
<Text className={Util.buildClassName(css[`icon-${this.state.movingItem.cell?.id}`], css.cell)}>
<div></div>
</Text>
</div>
)}
<Text>
TODO list:
</Text>
<ul>
<li><Text>Lancement Initial sans combo possible</Text></li>
<li><Text>Meilleurs Animation de destruction</Text></li>
<li><Text>Annuler le mouvement si rien n&apos;est claim</Text></li>
</ul>
</main>
)
private mouveMove = (ev: MouseEvent) => {
this.setState({cursorPos: {
x: ev.pageX,
y: ev.pageY
}})
}
private start() {
if (this.state.loading) {return}
this.setState({
loading: true,
items: Array
.from(Array(BOARD_SIZE))
.map(
() => Array.from(Array(BOARD_SIZE))
.map(() => ({id: random(0, ITEM_COUNT)}))
)
}, () => this.calculate())
}
private onCellClick = (x: number, y: number) => async () => {
// console.log(x, y)
if (this.state.loading) {
return window.alert('Cant play while Calculating')
}
if (!this.state.movingItem) {
const cell = this.state.items[y][x]
if (!cell) {
return window.alert('Cant move nothing')
}
document.addEventListener('mousemove', this.mouveMove)
this.setState({movingItem: {x,y,cell}})
this.state.items[y][x] = undefined
return
} else {
document.removeEventListener('mousemove', this.mouveMove)
const items = this.state.items
const temp = items[y][x]
items[y][x] = this.state.movingItem.cell
items[this.state.movingItem.y][this.state.movingItem.x] = temp
this.setState({
movingItem: undefined,
loading: true,
items
}, () => this.calculate())
}
}
private asyncSetState = (states: Partial<States>) => new Promise<void>(
(res) => this.setState(states as States, () => res())
)
private async calculate() {
const items = this.state.items.map((r) => r.map((c) => {
if (!c) {
return c
}
c.horizontalCombo = undefined
c.verticalCombo = undefined
return c
}))
let newPoints = 0
let checkupCount = 0
// Checkup horizontal
for (let y = 0; y < items.length; y++) {
const row = items[y]
for (let x = 0; x < row.length; x++) {
const cell = row[x]
if (!cell || cell.horizontalCombo) {continue}
const id = cell.id
let sameCount = 0
while((x + ++sameCount) < items.length) {
console.log(y + sameCount, x)
const tmp = row[x + sameCount]
if (!tmp || tmp.id !== id) {break}
}
if (sameCount >= 3) {
checkupCount += 1
for (let i = x; i < (x + sameCount); i++) {
const tmp = items[y][i]
if (!tmp) {continue}
tmp.horizontalCombo = true
newPoints++
}
}
}
}
// Check vertical
for (let y = 0; y < items.length; y++) {
const row = items[y]
for (let x = 0; x < row.length; x++) {
const cell = row[x]
if (!cell || cell.verticalCombo) {continue}
const id = cell.id
let sameCount = 0
while((y + ++sameCount) < items.length) {
// console.log(y + sameCount, x)
const tmp = items[y + sameCount][x]
if (!tmp || tmp.id !== id) {break}
}
// if ((y + sameCount) > items.length) {
// sameCount++
// }
if (sameCount >= 3) {
checkupCount += 1
for (let i = y; i < (y + sameCount); i++) {
const tmp = items[i][x]
if (!tmp) {continue}
tmp.verticalCombo = true
newPoints++
}
// console.log(x, y)
}
}
}
if (checkupCount) {
await this.asyncSetState({
items,
points: this.state.points + newPoints,
combo: this.state.combo+checkupCount,
comboMax: Math.max(this.state.comboMax, this.state.combo+checkupCount)
})
await new Promise((res) => setTimeout(res, 500))
}
// return
// Clear items
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let y = 0; y < items.length; y++) {
const row = items[y]
for (let x = 0; x < row.length; x++) {
const cell = row[x]
if (!cell || (!cell.horizontalCombo && !cell.verticalCombo)) {continue}
items[y][x] = undefined
}
}
let itemHasFallen = false
let needNewTurn = false
do {
// Make items fall
itemHasFallen = false
for (let y = (items.length - 1); y >= 0; y--) {
const row = items[y]
for (let x = 0; x < row.length; x++) {
const cell = row[x]
if (cell) {
cell.justSpawned = undefined
cell.isFalling = undefined
}
if (cell && y+1 < row.length && !items[y+1][x]) {
cell.isFalling = true
needNewTurn = true
itemHasFallen = true
items[y+1][x] = cell
items[y][x] = undefined
}
}
}
// Fill to top lane
for (let x = 0; x < items[0].length; x++) {
const cell = items[0][x]
if (!cell) {
itemHasFallen = true
items[0][x] = {id: random(0, ITEM_COUNT), justSpawned: true}
}
}
if (itemHasFallen) {
await this.asyncSetState({items})
await new Promise((res) => setTimeout(res, 300))
}
} while (itemHasFallen)
// If an item has fallen re calculate
if (needNewTurn) {
this.setState({items}, () => this.calculate())
return
}
this.setState({items, loading: undefined, turn: this.state.turn+1, combo: 0})
}
}
function random(min = 0, max = 100) {
return Math.floor(Math.random() * (max - min) + min)
}

View File

@ -0,0 +1,129 @@
$iconSize = 121px
.table
position relative
transition filter .5s ease-in-out
&.loading .cell
filter brightness(0.5)
.cellParent
position relative
width $iconSize
padding 0 !important
height $iconSize
.cell
width $iconSize
transition filter .5s ease-in-out
height $iconSize
background-image url('/assets/pokemon-shuffle/icons.png')
animation idleAnimation ease-in-out 1s
animation-iteration-count infinite
transform-origin 50% 50%
&.icon-0
background-position (1*$iconSize) 0px
&.icon-1
background-position (2*$iconSize) 0px
&.icon-2
background-position (3*$iconSize) 0px
&.icon-3
background-position (4*$iconSize) 0px
&.icon-4
background-position (5*$iconSize) 0px
&.icon-5
background-position (6*$iconSize) 0px
&.icon-6
background-position (7*$iconSize) 0px
&.icon-7
background-position (8*$iconSize) 0px
&.icon-8
background-position (9*$iconSize) 0px
&.icon-9
background-position (10*$iconSize) 0px
&.icon-10
background-position (11*$iconSize) 0px
&.isFalling
position absolute
animation fallingAnimation linear .3s
animation-iteration-count 1
transform-origin 50% 50%
animation-fill-mode forwards
&.explode
animation destroyAnimation ease-in-out .5s
animation-iteration-count 1
transform-origin 50% 50%
animation-fill-mode forwards
&::before
content " "
position absolute
bottom 0
width 100%
height 100%
border white solid 4px
border-radius 100%
animation destroyCircleAnimation ease-in-out .3s
animation-iteration-count 1
transform-origin 50% 50%
animation-fill-mode forwards
&.justSpawned
animation spawnAnimation ease-in-out 0.5s
animation-iteration-count 1
transform-origin 50% 50%
@keyframes idleAnimation
0%
transform rotate(0)
20%
transform rotate(-10deg)
40%
transform rotate(10deg)
60%
transform rotate(-5deg)
80%
transform rotate(5deg)
100%
transform rotate(0)
@keyframes fallingAnimation
from
top -117px // revoir précisément
to
top 3px
@keyframes destroyCircleAnimation
0%
opacity 0
transform scale(0)
100%
opacity 1
transform scale(1.2)
@keyframes destroyAnimation
0%
transform scale(1)
filter brightness(1)
20%
transform scale(1.3)
filter brightness(1.7)
100%
transform scale(0)
filter brightness(1.5)
@keyframes spawnAnimation
from
transform: scale(0)
to
transform: scale(1)

14
src/pages/sitemap.xml.ts Normal file
View File

@ -0,0 +1,14 @@
import { GetServerSideProps } from 'next'
import Sitemap from 'easy-sitemap'
export default class SitemapXml {}
export const getServerSideProps: GetServerSideProps = async ({res}) => {
const sitemap = new Sitemap('https://games.avior.me', {response: res})
sitemap.addEntry('/')
sitemap.addEntry('/pokemon-shuffle')
sitemap.build()
return {
notFound: true
}
}

38
tsconfig.json Normal file
View File

@ -0,0 +1,38 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"baseUrl": "./src",
"paths": {
"@styl/*": ["client/styl/*"],
"@cp/*": ["client/components/*"],
"@smd/*": ["client/styl/modules/*"],
}
},
"exclude": [
"node_modules",
"out",
"__tests__"
],
"include": [
"next-env.d.ts",
"src/client/styl/stylus.d.ts",
"**/*.ts",
"**/*.tsx"
]
}

7590
yarn.lock Normal file

File diff suppressed because it is too large Load Diff