mirror of
https://github.com/Aviortheking/games.git
synced 2025-04-23 03:12:09 +00:00
Updated code
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
This commit is contained in:
parent
f47ab40ffd
commit
cbfae26516
117
dzeio.next.config.js
Normal file
117
dzeio.next.config.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// V1.1.1 - Added futures blurry Placeholder and left optimizedLoading enabled
|
||||||
|
// Updated to commit from 2021-05-18
|
||||||
|
// https://github.com/vercel/next.js/commits/canary/packages/next/next-server/server/config-shared.ts
|
||||||
|
/**
|
||||||
|
* @type {import("next/dist/next-server/server/config-shared").NextConfig & import("next/dist/next-server/server/config-shared").defaultConfig}
|
||||||
|
*/
|
||||||
|
const nextConfig = {
|
||||||
|
// Experimentals
|
||||||
|
experimental: {
|
||||||
|
plugins: true,
|
||||||
|
profiling: process.env.NODE_ENV === 'developpment',
|
||||||
|
sprFlushToDisk: true,
|
||||||
|
workerThreads: true,
|
||||||
|
|
||||||
|
pageEnv: true,
|
||||||
|
optimizeImages: true,
|
||||||
|
optimizeCss: true,
|
||||||
|
|
||||||
|
scrollRestoration: true,
|
||||||
|
scriptLoader: true,
|
||||||
|
stats: process.env.NODE_ENV === 'developpment',
|
||||||
|
externalDir: true,
|
||||||
|
|
||||||
|
serialWebpackBuild: true,
|
||||||
|
|
||||||
|
conformance: true,
|
||||||
|
|
||||||
|
turboMode: true,
|
||||||
|
eslint: true,
|
||||||
|
// Bugged
|
||||||
|
// https://github.com/vercel/next.js/issues/18913
|
||||||
|
// reactRoot: true,
|
||||||
|
enableBlurryPlaceholder: true,
|
||||||
|
disableOptimizedLoading: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Non experimental config
|
||||||
|
// target: 'serverless',
|
||||||
|
poweredByHeader: false,
|
||||||
|
trailingSlash: false,
|
||||||
|
optimizeFonts: true,
|
||||||
|
reactStrictMode: true,
|
||||||
|
|
||||||
|
// Futures
|
||||||
|
future: {
|
||||||
|
webpack5: true,
|
||||||
|
strictPostcssConfiguration: true,
|
||||||
|
excludeDefaultMomentLocales: true
|
||||||
|
},
|
||||||
|
|
||||||
|
// Headers and rewrites
|
||||||
|
async headers() {
|
||||||
|
// CSS no CSP, x-xss-protection
|
||||||
|
const CSP = {
|
||||||
|
key: 'Content-Security-Policy',
|
||||||
|
value:
|
||||||
|
// default-src is set to self because prefetch-src is not working propelly see: https://bugs.chromium.org/p/chromium/issues/detail?id=801561
|
||||||
|
"default-src 'self'; " +
|
||||||
|
"frame-ancestors 'none'; " +
|
||||||
|
"form-action 'self'; " +
|
||||||
|
"manifest-src 'self'; " +
|
||||||
|
"prefetch-src 'self'; " +
|
||||||
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://stats.dzeio.com; " +
|
||||||
|
"style-src 'self' 'unsafe-inline'; " +
|
||||||
|
"img-src data: 'self'; " +
|
||||||
|
"font-src 'self'; " +
|
||||||
|
"connect-src 'self' https://stats.dzeio.com; " +
|
||||||
|
"base-uri 'self';"
|
||||||
|
}
|
||||||
|
const XXssProtection = {
|
||||||
|
key: 'X-XSS-Protection',
|
||||||
|
value: '1; mode=block'
|
||||||
|
}
|
||||||
|
// JS no x-xss-protection
|
||||||
|
|
||||||
|
const headers = [{
|
||||||
|
key: 'X-Frame-Options',
|
||||||
|
value: 'DENY'
|
||||||
|
}, {
|
||||||
|
key: 'X-Content-Type-Options',
|
||||||
|
value: 'nosniff'
|
||||||
|
}, {
|
||||||
|
key: 'Referrer-Policy',
|
||||||
|
value: 'strict-origin-when-cross-origin'
|
||||||
|
}, {
|
||||||
|
key: 'Permissions-Policy',
|
||||||
|
value: 'geolocation=(), microphone=(), interest-cohort=()'
|
||||||
|
}, {
|
||||||
|
key: 'Strict-Transport-Security',
|
||||||
|
value: 'max-age=63072000; includeSubDomains; preload'
|
||||||
|
}, {
|
||||||
|
key: 'X-Download-Options',
|
||||||
|
value: 'noopen'
|
||||||
|
}, {
|
||||||
|
key: 'Expect-CT',
|
||||||
|
value: 'max-age=86400, enforce'
|
||||||
|
}]
|
||||||
|
const excludedExtensions = ['js', 'css', 'json', 'ico', 'png']
|
||||||
|
.map((ext) => `(?!\\.${ext}$)`).join('|')
|
||||||
|
return [{
|
||||||
|
source: `/:path*((?!^\\/_next\\/image)|${excludedExtensions})`,
|
||||||
|
headers: [...headers, XXssProtection, CSP]
|
||||||
|
}, {
|
||||||
|
source: '/',
|
||||||
|
headers: [...headers, XXssProtection, CSP]
|
||||||
|
}, {
|
||||||
|
// No CSP, XXssProtection
|
||||||
|
source: `/:path*(\\.${excludedExtensions}$)`,
|
||||||
|
headers: headers
|
||||||
|
}, {
|
||||||
|
// No CSP, XXssProtection
|
||||||
|
source: '/_next/image',
|
||||||
|
headers: headers
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
module.exports = nextConfig
|
@ -1,10 +1,13 @@
|
|||||||
const stylus = require('@zeit/next-stylus')
|
// Add support for Stylus/LESS
|
||||||
const css = require('@zeit/next-css')
|
const preCSS = require('next-pre-css')
|
||||||
|
// Use Compose plugin for easier maintenance
|
||||||
const withPlugins = require('next-compose-plugins')
|
const withPlugins = require('next-compose-plugins')
|
||||||
|
|
||||||
const {PHASE_DEVELOPMENT_SERVER} = require('next/constants')
|
const {PHASE_DEVELOPMENT_SERVER} = require('next/constants')
|
||||||
|
const nextConfig = require('./dzeio.next.config')
|
||||||
|
|
||||||
module.exports = withPlugins([
|
module.exports = withPlugins([
|
||||||
[stylus, {
|
[preCSS, {
|
||||||
cssModules: true,
|
cssModules: true,
|
||||||
cssLoaderOptions: {
|
cssLoaderOptions: {
|
||||||
localIdentName: "[hash:base64:6]",
|
localIdentName: "[hash:base64:6]",
|
||||||
@ -14,9 +17,7 @@ module.exports = withPlugins([
|
|||||||
localIdentName: "[path][name]__[local]"
|
localIdentName: "[path][name]__[local]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}],
|
|
||||||
[css, {
|
|
||||||
cssModules: false
|
|
||||||
}]
|
}]
|
||||||
]
|
],
|
||||||
|
nextConfig
|
||||||
)
|
)
|
||||||
|
19
package.json
19
package.json
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@dzeio/url-shortener",
|
"name": "@avior/games",
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -10,31 +10,32 @@
|
|||||||
"test": "jest --config jext.config.js"
|
"test": "jest --config jext.config.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dzeio/components": "^0.2.1",
|
"@dzeio/components": "^0.10.1",
|
||||||
"@zeit/next-css": "^1.0.1",
|
"critters": "^0.0.10",
|
||||||
"@zeit/next-stylus": "^1.0.1",
|
|
||||||
"easy-sitemap": "^1.0.0",
|
"easy-sitemap": "^1.0.0",
|
||||||
"next": "^10.0.3",
|
"next": "^10.0.3",
|
||||||
"next-compose-plugins": "^2.2.0",
|
"next-compose-plugins": "^2.2.0",
|
||||||
|
"next-plausible": "^1.6.1",
|
||||||
|
"next-pre-css": "^1.0.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-feather": "^2.0.9",
|
"react-feather": "^2.0.9",
|
||||||
"stylus": "^0.54.7",
|
"stylus": "^0.54.7",
|
||||||
|
"stylus-loader": "^6.0.0",
|
||||||
"typescript": "^4.1.3",
|
"typescript": "^4.1.3",
|
||||||
"webpack": "^4.46.0"
|
"webpack": "^5.37.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.8.7",
|
"@babel/core": "^7.8.7",
|
||||||
"@types/favicons": "^6.2.0",
|
"@types/favicons": "^6.2.0",
|
||||||
"@types/node": "^14.0.0",
|
"@types/node": "^15.6.0",
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
||||||
"@typescript-eslint/parser": "^4.14.1",
|
"@typescript-eslint/parser": "^4.14.1",
|
||||||
"babel-preset-react-app": "^10.0.0",
|
|
||||||
"eslint": "^7.1.0",
|
"eslint": "^7.1.0",
|
||||||
|
"eslint-config-next": "^10.2.2",
|
||||||
"eslint-plugin-react": "^7.18.3",
|
"eslint-plugin-react": "^7.18.3",
|
||||||
"favicons": "^6.2.0",
|
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
"vercel": "^21.2.2"
|
"vercel": "^22.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import App from 'next/app'
|
import App from 'next/app'
|
||||||
|
|
||||||
|
import PlausibleProvider from 'next-plausible'
|
||||||
import '@dzeio/components/style.css'
|
import '@dzeio/components/style.css'
|
||||||
|
|
||||||
export default class CApp extends App {
|
export default class CApp extends App {
|
||||||
@ -8,6 +9,14 @@ export default class CApp extends App {
|
|||||||
public render() {
|
public render() {
|
||||||
const { Component, pageProps } = this.props
|
const { Component, pageProps } = this.props
|
||||||
|
|
||||||
return(<Component {...pageProps} />)
|
return (
|
||||||
|
<PlausibleProvider
|
||||||
|
domain="games.avior.me"
|
||||||
|
trackOutboundLinks
|
||||||
|
integrity="sha384-Bwk7iNMK9H56PgZeINNhN5Mk42LZoNIXe6Ztx5lfALsrTkNWC9yh2J2UFO0xShAv"
|
||||||
|
>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</PlausibleProvider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Link, Text } from '@dzeio/components'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
|
import { Link, Text } from '@dzeio/components'
|
||||||
|
|
||||||
export default class Index extends React.Component {
|
export default class Index extends React.Component {
|
||||||
|
|
||||||
public render = () => (
|
public render = () => (
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { Button, Table, Text, Util } from '@dzeio/components'
|
import { Button, Table, Text, Util, NotificationManager } from '@dzeio/components'
|
||||||
import React from 'react'
|
import React, { MouseEvent as ReactMouseEvent } from 'react'
|
||||||
import css from './pokemon-shuffle.styl'
|
import css from './pokemon-shuffle.module.styl'
|
||||||
|
|
||||||
interface Cell {
|
interface Cell {
|
||||||
id: number
|
id: number
|
||||||
|
id2: number
|
||||||
horizontalCombo?: true
|
horizontalCombo?: true
|
||||||
verticalCombo?: true
|
verticalCombo?: true
|
||||||
justSpawned?: true
|
justSpawned?: true
|
||||||
@ -14,7 +15,7 @@ interface States {
|
|||||||
items: Array<Array<Cell | undefined>>
|
items: Array<Array<Cell | undefined>>
|
||||||
loading?: true
|
loading?: true
|
||||||
movingItem?: {x: number, y: number, cell: Cell}
|
movingItem?: {x: number, y: number, cell: Cell}
|
||||||
points: number
|
damage: number
|
||||||
turn: number
|
turn: number
|
||||||
combo: number
|
combo: number
|
||||||
comboMax: number
|
comboMax: number
|
||||||
@ -29,30 +30,35 @@ export default class PokemonShuffle extends React.Component<unknown, States> {
|
|||||||
|
|
||||||
public state: States = {
|
public state: States = {
|
||||||
items: [[]],
|
items: [[]],
|
||||||
points: 0,
|
damage: 0,
|
||||||
turn: 0,
|
turn: 0,
|
||||||
combo: 0,
|
combo: 0,
|
||||||
comboMax: 0,
|
comboMax: 0,
|
||||||
cursorPos: {x: 0, y: 0}
|
cursorPos: {x: 0, y: 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async componentDidMount() {
|
||||||
|
await this.start()
|
||||||
|
}
|
||||||
|
|
||||||
public render = () => (
|
public render = () => (
|
||||||
<main>
|
<main>
|
||||||
<ul>
|
<ul>
|
||||||
<li><Text>Tour: {this.state.turn}</Text></li>
|
<li><Text>Tour: {this.state.turn}</Text></li>
|
||||||
<li><Text>Combo: {this.state.combo}, Max: {this.state.comboMax}</Text></li>
|
<li><Text>Combo: {this.state.combo}, Max: {this.state.comboMax}</Text></li>
|
||||||
<li><Text>Points: {this.state.points}</Text></li>
|
<li><Text>Points: {this.state.damage}</Text></li>
|
||||||
</ul>
|
</ul>
|
||||||
<Table >
|
<Table >
|
||||||
<tbody className={`${css.table} ${this.state.loading ? css.loading : ''}`}>
|
<tbody className={Util.buildClassName(css.table, [css.loading, this.state.loading])}>
|
||||||
{this.state.items.map((row, y) => (
|
{this.state.items.map((row, y) => (
|
||||||
<tr key={y}>
|
<tr key={y}>
|
||||||
{row.map((cell, x) => (
|
{row.map((cell, x) => (
|
||||||
<td
|
<td
|
||||||
key={cell?.isFalling ? n++ : x}
|
key={cell?.id2 ?? x}
|
||||||
onClick={this.onCellClick(x, y)}
|
onClick={this.onCellClick(x, y)}
|
||||||
className={css.cellParent}
|
className={css.cellParent}
|
||||||
>
|
>
|
||||||
|
{/* <Text>{JSON.stringify(cell)}</Text> */}
|
||||||
{cell && (
|
{cell && (
|
||||||
<Text className={Util.buildClassName(
|
<Text className={Util.buildClassName(
|
||||||
css[`icon-${cell.id}`],
|
css[`icon-${cell.id}`],
|
||||||
@ -70,16 +76,11 @@ export default class PokemonShuffle extends React.Component<unknown, States> {
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
<Button onClick={() => this.calculate()}>Calculate!</Button>
|
<Button onClick={this.start}>Start!</Button>
|
||||||
<Button onClick={() => this.start()}>Start!</Button>
|
|
||||||
{/* <Input block type="textarea" value={JSON.stringify(this.state.items)}/> */}
|
|
||||||
{this.state.movingItem && (
|
{this.state.movingItem && (
|
||||||
<div style={{
|
<div className={css.hoverItem} style={{
|
||||||
position: 'absolute',
|
|
||||||
left: this.state.cursorPos.x,
|
left: this.state.cursorPos.x,
|
||||||
top: this.state.cursorPos.y,
|
top: this.state.cursorPos.y
|
||||||
transform: 'translate(-50%, -50%)',
|
|
||||||
pointerEvents: 'none'
|
|
||||||
}}>
|
}}>
|
||||||
<Text className={Util.buildClassName(css[`icon-${this.state.movingItem.cell?.id}`], css.cell)}>
|
<Text className={Util.buildClassName(css[`icon-${this.state.movingItem.cell?.id}`], css.cell)}>
|
||||||
<div></div>
|
<div></div>
|
||||||
@ -90,46 +91,52 @@ export default class PokemonShuffle extends React.Component<unknown, States> {
|
|||||||
TODO list:
|
TODO list:
|
||||||
</Text>
|
</Text>
|
||||||
<ul>
|
<ul>
|
||||||
<li><Text>Lancement Initial sans combo possible</Text></li>
|
<li><Text>Faire que les clear ce fasse de manière Async</Text></li>
|
||||||
<li><Text>Meilleurs Animation de destruction</Text></li>
|
<li><Text>Meilleurs Animation de destruction</Text></li>
|
||||||
<li><Text>Annuler le mouvement si rien n'est claim</Text></li>
|
<li><Text>Annuler le mouvement si rien n'est claim</Text></li>
|
||||||
|
<li><Text>Utiliser le système de damages de Pokémon Shuffle https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_Shuffle#Damage</Text></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<NotificationManager />
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
|
|
||||||
private mouveMove = (ev: MouseEvent) => {
|
private mouveMove = (ev: MouseEvent) => {
|
||||||
this.setState({cursorPos: {
|
this.setState({cursorPos: {
|
||||||
x: ev.pageX,
|
x: ev.clientX,
|
||||||
y: ev.pageY
|
y: ev.clientY
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
|
|
||||||
private start() {
|
private start = async () => {
|
||||||
if (this.state.loading) {return}
|
if (this.state.loading) {return}
|
||||||
this.setState({
|
await this.asyncSetState({
|
||||||
loading: true,
|
loading: true,
|
||||||
|
// generate datas
|
||||||
items: Array
|
items: Array
|
||||||
.from(Array(BOARD_SIZE))
|
.from(Array(BOARD_SIZE))
|
||||||
.map(
|
.map(
|
||||||
() => Array.from(Array(BOARD_SIZE))
|
() => Array.from(Array(BOARD_SIZE))
|
||||||
.map(() => ({id: random(0, ITEM_COUNT)}))
|
.map(() => ({id: random(0, ITEM_COUNT), id2: n++}))
|
||||||
)
|
)
|
||||||
}, () => this.calculate())
|
})
|
||||||
|
// Quickly calculate everythings to make it look like it was perfecly generated
|
||||||
|
await this.calculate(true)
|
||||||
|
this.setState({turn: 1, damage: 0, comboMax: 0, combo: 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
private onCellClick = (x: number, y: number) => async () => {
|
private onCellClick = (x: number, y: number) => async (ev: ReactMouseEvent) => {
|
||||||
// console.log(x, y)
|
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
return window.alert('Cant play while Calculating')
|
return NotificationManager.addNotification('Cant play while Calculating')
|
||||||
}
|
}
|
||||||
if (!this.state.movingItem) {
|
if (!this.state.movingItem) {
|
||||||
const cell = this.state.items[y][x]
|
const cell = this.state.items[y][x]
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
return window.alert('Cant move nothing')
|
return NotificationManager.addNotification('Cant move nothing')
|
||||||
}
|
}
|
||||||
document.addEventListener('mousemove', this.mouveMove)
|
document.addEventListener('mousemove', this.mouveMove)
|
||||||
this.setState({movingItem: {x,y,cell}})
|
this.setState({movingItem: {x,y,cell}})
|
||||||
this.state.items[y][x] = undefined
|
this.state.items[y][x] = undefined
|
||||||
|
this.mouveMove(ev.nativeEvent)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
document.removeEventListener('mousemove', this.mouveMove)
|
document.removeEventListener('mousemove', this.mouveMove)
|
||||||
@ -150,102 +157,97 @@ export default class PokemonShuffle extends React.Component<unknown, States> {
|
|||||||
(res) => this.setState(states as States, () => res())
|
(res) => this.setState(states as States, () => res())
|
||||||
)
|
)
|
||||||
|
|
||||||
private async calculate() {
|
/**
|
||||||
const items = this.state.items.map((r) => r.map((c) => {
|
* Check if items has combos
|
||||||
if (!c) {
|
* @returns if items were changed
|
||||||
return c
|
*/
|
||||||
}
|
private async checkup(): Promise<boolean> {
|
||||||
c.horizontalCombo = undefined
|
const items = this.state.items
|
||||||
c.verticalCombo = undefined
|
|
||||||
return c
|
|
||||||
}))
|
|
||||||
|
|
||||||
let newPoints = 0
|
|
||||||
|
|
||||||
let checkupCount = 0
|
let checkupCount = 0
|
||||||
// Checkup horizontal
|
let newPoints = 0
|
||||||
for (let y = 0; y < items.length; y++) {
|
for (let y = 0; y < items.length; y++) {
|
||||||
const row = items[y]
|
const row = items[y]
|
||||||
for (let x = 0; x < row.length; x++) {
|
for (let x = 0; x < row.length; x++) {
|
||||||
const cell = row[x]
|
const cell = row[x]
|
||||||
if (!cell || cell.horizontalCombo) {continue}
|
if (!cell) {continue}
|
||||||
const id = cell.id
|
const id = cell.id
|
||||||
|
// Checkup horizontal
|
||||||
|
if (!cell.horizontalCombo && !(cell.isFalling || cell.justSpawned)) {
|
||||||
let sameCount = 0
|
let sameCount = 0
|
||||||
while((x + ++sameCount) < items.length) {
|
while((x + ++sameCount) < items.length) {
|
||||||
console.log(y + sameCount, x)
|
console.log(y + sameCount, x)
|
||||||
const tmp = row[x + sameCount]
|
const tmp = row[x + sameCount]
|
||||||
if (!tmp || tmp.id !== id) {break}
|
if (!tmp || tmp.id !== id || tmp.isFalling || tmp.justSpawned) {break}
|
||||||
}
|
}
|
||||||
if (sameCount >= 3) {
|
if (sameCount >= 3) {
|
||||||
checkupCount += 1
|
checkupCount += 1
|
||||||
|
let len = 0
|
||||||
for (let i = x; i < (x + sameCount); i++) {
|
for (let i = x; i < (x + sameCount); i++) {
|
||||||
const tmp = items[y][i]
|
const tmp = items[y][i]
|
||||||
if (!tmp) {continue}
|
if (!tmp) {continue}
|
||||||
tmp.horizontalCombo = true
|
tmp.horizontalCombo = true
|
||||||
newPoints++
|
len++
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
newPoints += calculateScore(len, this.state.combo)
|
||||||
|
|
||||||
// Check vertical
|
}
|
||||||
for (let y = 0; y < items.length; y++) {
|
}
|
||||||
const row = items[y]
|
// Checkup Vertical
|
||||||
for (let x = 0; x < row.length; x++) {
|
if (!cell.verticalCombo && !(cell.isFalling || cell.justSpawned)) {
|
||||||
const cell = row[x]
|
|
||||||
if (!cell || cell.verticalCombo) {continue}
|
|
||||||
const id = cell.id
|
|
||||||
let sameCount = 0
|
let sameCount = 0
|
||||||
while((y + ++sameCount) < items.length) {
|
while((y + ++sameCount) < items.length) {
|
||||||
// console.log(y + sameCount, x)
|
// console.log(y + sameCount, x)
|
||||||
const tmp = items[y + sameCount][x]
|
const tmp = items[y + sameCount][x]
|
||||||
if (!tmp || tmp.id !== id) {break}
|
if (!tmp || tmp.id !== id || tmp.isFalling || tmp.justSpawned) {break}
|
||||||
}
|
}
|
||||||
// if ((y + sameCount) > items.length) {
|
|
||||||
// sameCount++
|
|
||||||
// }
|
|
||||||
if (sameCount >= 3) {
|
if (sameCount >= 3) {
|
||||||
checkupCount += 1
|
checkupCount += 1
|
||||||
|
let len = 0
|
||||||
for (let i = y; i < (y + sameCount); i++) {
|
for (let i = y; i < (y + sameCount); i++) {
|
||||||
const tmp = items[i][x]
|
const tmp = items[i][x]
|
||||||
if (!tmp) {continue}
|
if (!tmp) {continue}
|
||||||
tmp.verticalCombo = true
|
tmp.verticalCombo = true
|
||||||
|
len++
|
||||||
newPoints++
|
|
||||||
}
|
}
|
||||||
|
newPoints += calculateScore(len, this.state.combo)
|
||||||
// console.log(x, y)
|
// console.log(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If combos were found
|
||||||
if (checkupCount) {
|
if (checkupCount) {
|
||||||
|
const combo = this.state.combo + checkupCount
|
||||||
await this.asyncSetState({
|
await this.asyncSetState({
|
||||||
items,
|
items,
|
||||||
points: this.state.points + newPoints,
|
damage: this.state.damage + newPoints,
|
||||||
combo: this.state.combo+checkupCount,
|
combo,
|
||||||
comboMax: Math.max(this.state.comboMax, this.state.combo+checkupCount)
|
comboMax: Math.max(this.state.comboMax, combo)
|
||||||
})
|
})
|
||||||
await new Promise((res) => setTimeout(res, 500))
|
}
|
||||||
|
return !!checkupCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// return
|
private async endTurn(state?: Partial<States>) {
|
||||||
|
await this.asyncSetState({...state, loading: undefined, turn: this.state.turn + 1, combo: 0})
|
||||||
// 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
|
private async calculate(initial = false) {
|
||||||
let needNewTurn = false
|
// remove combos
|
||||||
|
const items = this.state.items.map((r) => r.map((c) => {
|
||||||
|
if (!c) {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
delete c.horizontalCombo
|
||||||
|
delete c.verticalCombo
|
||||||
|
return c
|
||||||
|
}))
|
||||||
|
|
||||||
|
let needContinue = false
|
||||||
do {
|
do {
|
||||||
// Make items fall
|
// Make items fall
|
||||||
itemHasFallen = false
|
needContinue = false
|
||||||
for (let y = (items.length - 1); y >= 0; y--) {
|
for (let y = (items.length - 1); y >= 0; y--) {
|
||||||
const row = items[y]
|
const row = items[y]
|
||||||
for (let x = 0; x < row.length; x++) {
|
for (let x = 0; x < row.length; x++) {
|
||||||
@ -256,37 +258,107 @@ export default class PokemonShuffle extends React.Component<unknown, States> {
|
|||||||
}
|
}
|
||||||
if (cell && y+1 < row.length && !items[y+1][x]) {
|
if (cell && y+1 < row.length && !items[y+1][x]) {
|
||||||
cell.isFalling = true
|
cell.isFalling = true
|
||||||
needNewTurn = true
|
needContinue = true
|
||||||
itemHasFallen = true
|
// Move cell down
|
||||||
items[y+1][x] = cell
|
items[y+1][x] = cell
|
||||||
items[y][x] = undefined
|
items[y][x] = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill to top lane
|
// Fill the top lane
|
||||||
for (let x = 0; x < items[0].length; x++) {
|
for (let x = 0; x < items[0].length; x++) {
|
||||||
const cell = items[0][x]
|
const cell = items[0][x]
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
itemHasFallen = true
|
needContinue = true
|
||||||
items[0][x] = {id: random(0, ITEM_COUNT), justSpawned: true}
|
items[0][x] = {id: random(0, ITEM_COUNT), id2: n++, justSpawned: true}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (itemHasFallen) {
|
|
||||||
await this.asyncSetState({items})
|
|
||||||
await new Promise((res) => setTimeout(res, 300))
|
|
||||||
}
|
|
||||||
} while (itemHasFallen)
|
|
||||||
|
|
||||||
// If an item has fallen re calculate
|
// Need to wait for the falling animation
|
||||||
if (needNewTurn) {
|
if (needContinue) {
|
||||||
this.setState({items}, () => this.calculate())
|
await this.asyncSetState({items})
|
||||||
return
|
if (!initial) {
|
||||||
|
await wait(300)
|
||||||
}
|
}
|
||||||
this.setState({items, loading: undefined, turn: this.state.turn+1, combo: 0})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checkup if there is combos
|
||||||
|
const checkup = await this.checkup()
|
||||||
|
if (!checkup && !needContinue) {
|
||||||
|
return await this.endTurn({items})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear items
|
||||||
|
let hasCleared = false
|
||||||
|
for (const row of items) {
|
||||||
|
for (let x = 0; x < row.length; x++) {
|
||||||
|
const cell = row[x]
|
||||||
|
if (!cell || (!cell.horizontalCombo && !cell.verticalCombo)) {continue}
|
||||||
|
row[x] = undefined
|
||||||
|
hasCleared = true
|
||||||
|
needContinue = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCleared && !initial) {
|
||||||
|
await wait(500)
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (needContinue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateScore(len: number, combo: number) {
|
||||||
|
let score = len * 40 // currently the damage
|
||||||
|
if (len > 3) {
|
||||||
|
switch (len) {
|
||||||
|
case 4:
|
||||||
|
score *= 1.5
|
||||||
|
break
|
||||||
|
case 5:
|
||||||
|
score *= 2
|
||||||
|
break
|
||||||
|
case 6:
|
||||||
|
score *= 3
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (combo > 1) {
|
||||||
|
if (combo >= 2 && combo <= 4) {
|
||||||
|
score *= 1.1
|
||||||
|
}
|
||||||
|
if (combo >= 5 && combo <= 9) {
|
||||||
|
score *= 1.1
|
||||||
|
}
|
||||||
|
if (combo >= 10 && combo <= 24) {
|
||||||
|
score *= 1.2
|
||||||
|
}
|
||||||
|
if (combo >= 25 && combo <= 49) {
|
||||||
|
score *= 1.3
|
||||||
|
}
|
||||||
|
if (combo >= 50 && combo <= 74) {
|
||||||
|
score *= 1.4
|
||||||
|
}
|
||||||
|
if (combo >= 75 && combo <= 99) {
|
||||||
|
score *= 1.5
|
||||||
|
}
|
||||||
|
if (combo >= 100 && combo <= 199) {
|
||||||
|
score *= 2
|
||||||
|
}
|
||||||
|
if (combo >= 200) {
|
||||||
|
score *= 2.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score
|
||||||
}
|
}
|
||||||
|
|
||||||
function random(min = 0, max = 100) {
|
function random(min = 0, max = 100) {
|
||||||
return Math.floor(Math.random() * (max - min) + min)
|
return Math.floor(Math.random() * (max - min) + min)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wait(time: number): Promise<void> {
|
||||||
|
return new Promise((res) => setTimeout(() => res(), time))
|
||||||
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
$iconSize = 121px
|
$iconSize = 121px
|
||||||
|
|
||||||
|
.hoverItem
|
||||||
|
position fixed
|
||||||
|
transform translate(-50%, -50%)
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
.table
|
.table
|
||||||
position relative
|
position relative
|
||||||
transition filter .5s ease-in-out
|
transition filter .5s ease-in-out
|
||||||
@ -21,28 +26,9 @@ $iconSize = 121px
|
|||||||
animation idleAnimation ease-in-out 1s
|
animation idleAnimation ease-in-out 1s
|
||||||
animation-iteration-count infinite
|
animation-iteration-count infinite
|
||||||
transform-origin 50% 50%
|
transform-origin 50% 50%
|
||||||
&.icon-0
|
for num in (0..30)
|
||||||
background-position (1*$iconSize) 0px
|
&.icon-{num}
|
||||||
&.icon-1
|
background-position ((num + 1) * $iconSize) 0px
|
||||||
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
|
&.isFalling
|
||||||
position absolute
|
position absolute
|
||||||
@ -94,7 +80,7 @@ $iconSize = 121px
|
|||||||
from
|
from
|
||||||
top -117px // revoir précisément
|
top -117px // revoir précisément
|
||||||
to
|
to
|
||||||
top 3px
|
top 0
|
||||||
|
|
||||||
@keyframes destroyCircleAnimation
|
@keyframes destroyCircleAnimation
|
||||||
0%
|
0%
|
Loading…
x
Reference in New Issue
Block a user