-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
307 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap'); | ||
|
||
* { | ||
box-sizing: border-box; | ||
} | ||
|
||
html { | ||
font-size: 16px; | ||
min-width: 100%; | ||
min-height: 100%; | ||
overflow-x: hidden; | ||
} | ||
|
||
body { | ||
margin: 0; | ||
padding: 0; | ||
font-family: 'Inter', sans-serif; | ||
background-color: #f5f5f5; | ||
|
||
width: 100vw; | ||
height: 100vh; | ||
} | ||
|
||
/* App */ | ||
.app { | ||
display: flex; | ||
flex-direction: row; | ||
min-height: 100%; | ||
} | ||
|
||
/* Shop */ | ||
.store { | ||
display: flex; | ||
flex-direction: column; | ||
flex: 1; | ||
min-height: 100%; | ||
max-width: 20rem; | ||
|
||
background-color: #eee; | ||
border-right: 1px dotted #ccc; | ||
} | ||
|
||
.store .store__elements { | ||
list-style: none; | ||
margin: 0; | ||
padding: 0; | ||
} | ||
|
||
.store .store__elements .item { | ||
display: block; | ||
margin: 1rem; | ||
position: relative; | ||
} | ||
.store .store__elements .item .item__details { | ||
position: absolute; | ||
z-index: 999; | ||
left: 0; | ||
top: 100%; | ||
margin-top: .25rem; | ||
transform: translateY(-1rem); | ||
padding: .5rem 1rem; | ||
background-color: rgba(0, 0, 0, 0.6); | ||
color: #fff; | ||
user-select: none; | ||
pointer-events: none; | ||
opacity: 0; | ||
transition: opacity .2s ease-in-out, transform .2s ease-in-out; | ||
} | ||
.store .store__elements .item:hover .item__details { | ||
opacity: 1; | ||
transform: translateY(0); | ||
} | ||
|
||
.store .store__elements .item .item__buy { | ||
display: block; | ||
width: 100%; | ||
padding: 1rem 1rem; | ||
border: none; | ||
text-align: left; | ||
background-color: rgb(26, 173, 75); | ||
font-family: 'Inter', sans-serif; | ||
color: white; | ||
} | ||
|
||
/* Main area */ | ||
.content { | ||
display: flex; | ||
flex-direction: column; | ||
flex: 1; | ||
min-height: 100%; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
|
||
.content .content__button { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
.content .content__button #clicks { | ||
font-size: 2rem; | ||
font-weight: 700; | ||
margin-bottom: 1rem; | ||
} | ||
.content .content__button #clicks::after { | ||
content: '⚡'; | ||
} | ||
|
||
.content .content__button #clicker { | ||
margin-top: 1rem; | ||
background-color: transparent; | ||
border: none; | ||
cursor: pointer; | ||
animation: rotate 2s infinite ease-in-out; | ||
} | ||
.content .content__button #clicker .clicker__emoji { | ||
display: block; | ||
margin: 0 auto; | ||
font-size: 10rem; | ||
line-height: 1; | ||
transition: transform .2s ease-in-out; | ||
} | ||
.content .content__button #clicker:hover .clicker__emoji { | ||
transform: scale(1.1); | ||
} | ||
.content .content__button #clicker:active .clicker__emoji { | ||
transform: scale(1); | ||
} | ||
|
||
/* Animations */ | ||
@keyframes rotate { | ||
0% { | ||
transform: rotate(-5deg); | ||
} | ||
50% { | ||
transform: rotate(5deg); | ||
} | ||
100% { | ||
transform: rotate(-5deg); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,133 @@ | ||
import Store from "./store.js"; | ||
|
||
/** | ||
* Class representing the game. | ||
*/ | ||
export default class Game { | ||
/** | ||
* @param {string} id The id of the button | ||
* | ||
* @property {HTMLElement} button The button | ||
* @property {number} clicks The number of clicks | ||
* @property {number} clicksMultiplier The multiplier of the clicks | ||
* @property {number} clicksPerSecondAdder The number of clicks per second added by the upgrades | ||
* @property {number} cps The number of clicks per second of the user | ||
* @property {number} lastClickTime The time of the last click | ||
* @property {Store} store The store associated with the game | ||
* Creates an instance of Game. | ||
* @param {string} id - The id of the button. | ||
*/ | ||
constructor(id) { | ||
/* Properties */ | ||
this.button = document.getElementById(id); | ||
this.clicks = 0; | ||
this.clicksMultiplier = 1; | ||
this.clicksPerSecondAdder = 0; | ||
this.cps = 0; | ||
this.clicksAdder = 0; | ||
this.lastClickTime = 0; | ||
this.store = null; | ||
|
||
this.clickIntervals = []; | ||
this.maxSameInterval = 8; | ||
this.intervalFunction = null; | ||
|
||
this.regularityCounter = 0; | ||
this.regularityThreshold = 10; // If the player is too regular and gets a regularityCounter > regularityThreshold, he's most likely cheating | ||
|
||
/* Binds */ | ||
this.button.addEventListener("click", this.clickHandler.bind(this)); | ||
setInterval(this.interval.bind(this), 1000); | ||
this.intervalFunction = setInterval(this.interval.bind(this), 1000); | ||
} | ||
|
||
/* Methods */ | ||
/** | ||
* Interval CPS adder | ||
* Interval handler. | ||
*/ | ||
interval() { | ||
this.clicks += this.clicksPerSecondAdder; | ||
this.renderSpan(); | ||
} | ||
|
||
/** | ||
* Displays the amount of clicks on the screen | ||
* Displays the amount of clicks on the screen. | ||
*/ | ||
renderSpan() { | ||
document.getElementById("clicks").textContent = this.clicks; | ||
} | ||
|
||
/** | ||
* Handles the click event | ||
* Handles the click event. | ||
* @param {Event} e - The click event. | ||
*/ | ||
clickHandler() { | ||
clickHandler(e) { | ||
const currentTime = Date.now(); | ||
const timeSinceLastClick = currentTime - this.lastClickTime; | ||
if (timeSinceLastClick > 0) { | ||
this.cps = 1000 / timeSinceLastClick; | ||
|
||
this.clickIntervals.push(timeSinceLastClick); | ||
|
||
if (this.clickIntervals.length > this.maxSameInterval) { | ||
this.clickIntervals.shift(); | ||
} | ||
|
||
this.clicks += 1 * this.clicksMultiplier; | ||
this.clicks += 1 + this.clicksAdder; | ||
this.lastClickTime = currentTime; | ||
|
||
this.renderSpan(); | ||
this.cheatDetector(); | ||
this.cheatDetector(e); | ||
} | ||
|
||
/** | ||
* Detects if the user is cheating and clicking in a humanly impossible way | ||
* Detects if the user is cheating and clicking in a humanly impossible way. | ||
* @param {Event} e - The click event. | ||
*/ | ||
cheatDetector() { | ||
const maxCPS = 22; | ||
if (this.cps > maxCPS) { | ||
this.clicks = 0; | ||
this.clicksPerSecondAdder = 0; | ||
this.cps = 0; | ||
this.lastClickTime = 0; | ||
|
||
this.button.removeEventListener("click", this.clickHandler); | ||
alert("You're cheating!"); | ||
cheatDetector(e) { | ||
const irregularityTolerance = 10; // ms | ||
|
||
if (this.checkRegularIntervals(irregularityTolerance)) { | ||
this.regularityCounter++; | ||
} | ||
|
||
if (!e.isTrusted) return this.cheating(); // Instant ban | ||
if (this.regularityCounter > this.regularityThreshold) { | ||
console.warn("You're clicking too regularly, you're most likely cheating."); | ||
this.cheating(); | ||
} | ||
} | ||
|
||
/** | ||
* Sets a store to the game | ||
* A cheating behavior is detected, the game is stopped. | ||
*/ | ||
cheating() { | ||
clearInterval(this.intervalFunction); | ||
this.button.remove(); | ||
this.resetGameProperties(); | ||
document.body.innerHTML = "You're cheating, shame on you!"; | ||
} | ||
|
||
/** | ||
* Sets a store to the game. | ||
* @param {string} storeID - The id of the store. | ||
*/ | ||
setStore(storeID) { | ||
this.store = new Store(storeID, this); | ||
} | ||
|
||
/** | ||
* Verifies if clicks are legit by checking their regularity. | ||
* @param {number} tolerance - The tolerance of irregularity. | ||
* @returns {boolean} - True if clicks are too regular, false otherwise. | ||
*/ | ||
checkRegularIntervals(tolerance) { | ||
const intervals = this.clickIntervals; | ||
const averageInterval = intervals.reduce((sum, interval) => sum + interval, 0) / intervals.length; | ||
|
||
for (let i = 0; i < this.clickIntervals.length; i++) { | ||
const difference = Math.abs(this.clickIntervals[i] - averageInterval); | ||
if (difference > tolerance) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Resets game properties to their initial values. | ||
*/ | ||
resetGameProperties() { | ||
this.clicks = 0; | ||
this.clicksAdder = 0; | ||
this.lastClickTime = 0; | ||
this.store = null; | ||
this.clickIntervals = []; | ||
this.maxSameInterval = 8; | ||
this.intervalFunction = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,25 @@ | ||
/** | ||
* Note: all numbers must be integers, not floats. | ||
* Available properties: | ||
* - name: name of the item | ||
* - text: text displayed in the button | ||
* - price: price of the item | ||
* - maxQuantity: max quantity of the item (default: Infinity) | ||
* - cpsAdder: CPS added by the item (default: 0) | ||
* - cpsAdderMultiplier: multiplier of the CPS added by the item (default: 2) | ||
* - clicksAdder: clicks added by the item (default: 0) | ||
*/ | ||
export default [ | ||
{ | ||
name: "Server", | ||
text: "+{{cpsAdder}} cps", | ||
|
||
text: "+ {{clicksAdder}} to each click", | ||
price: 10, | ||
clicksAdder: 1, | ||
}, | ||
{ | ||
name: "Developer", | ||
text: "+ {{cpsAdder}}/s", | ||
price: 100, | ||
cpsAdder: 1, | ||
quantity: 0, | ||
// maxQuantity: 1, | ||
|
||
cpsAdderMultiplier: 2, | ||
} | ||
]; |
Oops, something went wrong.