mirror of
https://gitlab.com/lecarore/breakout71.git
synced 2025-04-23 21:46:15 -04:00
Compare commits
46 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3d3e7805d6 | ||
![]() |
2c8a710aab | ||
![]() |
af65737011 | ||
![]() |
bf3dac8e8f | ||
![]() |
6429c85a4b | ||
![]() |
dc66f69543 | ||
![]() |
6b54fb82d6 | ||
![]() |
88d746e7a1 | ||
![]() |
3a9e06207e | ||
![]() |
49f3769b54 | ||
![]() |
5ba93500b4 | ||
![]() |
6b6e393d3b | ||
![]() |
0a1d9dfe2f | ||
![]() |
9716235531 | ||
![]() |
2b29c0275a | ||
![]() |
419bd8e26b | ||
![]() |
44b9a39927 | ||
![]() |
f1cd138071 | ||
![]() |
de485e5598 | ||
![]() |
ae2f43be0e | ||
![]() |
0cfd75e7b2 | ||
![]() |
c88540488d | ||
![]() |
b3949d8c41 | ||
![]() |
4d7d57f17f | ||
![]() |
1ba55bf2a6 | ||
![]() |
70f3c2307a | ||
![]() |
66952cb1ca | ||
![]() |
a386c5f3d2 | ||
![]() |
6adab3d07f | ||
![]() |
603ebf319a | ||
![]() |
1252bbca06 | ||
![]() |
b891e0fafb | ||
![]() |
a388cd0898 | ||
![]() |
d43dd90a86 | ||
![]() |
530e94f704 | ||
![]() |
21fa5f105e | ||
![]() |
277aa5682b | ||
![]() |
871a7f9c31 | ||
![]() |
8e4e67e33b | ||
![]() |
06843047d2 | ||
![]() |
354a6490e9 | ||
![]() |
47ad04c49b | ||
![]() |
64a85200b9 | ||
![]() |
11c797bc59 | ||
![]() |
0cb4945e7d | ||
![]() |
2d383f02cb |
44 changed files with 10009 additions and 1682 deletions
113
Readme.md
113
Readme.md
|
@ -11,24 +11,97 @@ Break colourful bricks, catch bouncing coins and select powerful upgrades !
|
|||
- [Google Play](https://play.google.com/store/apps/details?id=me.lecaro.breakout)
|
||||
- [GitLab](https://gitlab.com/lecarore/breakout71)
|
||||
|
||||
# Current priorities
|
||||
|
||||
The goal of this project is to make a game used by many people. The game is already pretty fun. I'm now trying to
|
||||
translate it to (Lebanese) Arabic, Russian and (Chilean) Spanish. Other translation are very welcome, contact me
|
||||
if you'd like to submit one.
|
||||
|
||||
While translations are being written, I'll try to avoid adding features that require new translations. That means only
|
||||
bug fixes and optimisations, maybe adding levels. Once we have a nice stable release available in 4
|
||||
languages, I may add features again.
|
||||
|
||||
|
||||
# Changelog
|
||||
## To do
|
||||
|
||||
- auto-detect device performance at first startup and adjust settings accordingly
|
||||
|
||||
## Done
|
||||
|
||||
- new perk: happy family: + lvl points per paddle bounce per extra ball, reset on ball lost
|
||||
- nerfed perk : sticky coins : stick to same color at level 1, any color at level 2+
|
||||
- nerfed perk: zen : combo increases every 3 seconds, resets on explosion
|
||||
|
||||
## 29088513
|
||||
|
||||
- included german corrections by Pock
|
||||
- added particle effect for wrap
|
||||
- removed grace period from passive income, updated icon
|
||||
|
||||
## 29087440
|
||||
|
||||
- zen : now you gain one combo per bomb on screen when breaking a brick (so no bombs, no gain)
|
||||
- sticky coins : coins stay stuck when there's an explosion
|
||||
- wrap_left / wrap_right : teleport the ball to the other side of the screen when it hits a border
|
||||
- passive income : now moving the puck makes it transparent to coins and balls, but not reset the combo
|
||||
- main menu : split level unlock and perks unlocks
|
||||
|
||||
## 29087252
|
||||
- apply percentage boost to combo shown on brick
|
||||
- smaller puck now gives +50% coins per level
|
||||
- transparency now gives +50% coins if ALL balls are fully transparent, less otherwise
|
||||
- new perk : sticky coins (coins stick to bricks)
|
||||
- left/top/right is laval perks : at level 2+, the corresponding borders completely disappears (reachable with limitless)
|
||||
- new perk : three cushion (gain point for indirect hits)
|
||||
- live stats: coins still in the air appear as "lost" in the catch percentage, as in the final computation
|
||||
- level editor : removed the conditions on bricks count, level name and credits to be able to copy the code
|
||||
- shadow around ball when there are many coins : enabled in basic mode too
|
||||
- hot start : after reset, if you raise the combo again, only start ticking down after a whole second.
|
||||
- new perk : ottawa treaty, breaking a brick near a bomb disarms the bomb
|
||||
- shocks now doesn't add ball speed at level 1
|
||||
- creative mode UI rework
|
||||
- compound_interest : combo resets as soon as coin passes the paddle line
|
||||
- added bombs to implosion and kaboom starter levels
|
||||
- toast an error if storage is blocked
|
||||
- toast an error if migration fails
|
||||
- fixed video download in apk
|
||||
- ask for permanent storage
|
||||
- option: reuse past frame's light in new frame lighting computation when there are 150+ coins on screen, to limit the performance impact of rendering lots of lights
|
||||
|
||||
## 29084606
|
||||
|
||||
- simpler and more readable encoding for save files
|
||||
- removed check of payload signature on save file, seemed to fail because of the poor encoding of the name of the "côte d'ivoire" level
|
||||
- automatic detection of the number of steps required for physics
|
||||
- trial runs detection fix
|
||||
|
||||
## 29083397
|
||||
|
||||
- highlight last used creative level
|
||||
- access autoplay mode from the menu
|
||||
- access stress test mode from the menu, show real time stats
|
||||
- Render bottom border differently to show how far the puck can go
|
||||
- Corner Shot: scale like Need Some Space
|
||||
- grey out irrelevant options in the settings
|
||||
- Back to Creative Menu at the end of a Creative level
|
||||
|
||||
## 29080170
|
||||
|
||||
- don't show unlock toast at first startup for levels that are unlocked by default
|
||||
- Droplet particle color should be gold for gold coins
|
||||
- added levels: A Very Dangerous High-Five, The Boys
|
||||
|
||||
## 29079818
|
||||
|
||||
- Imported levels : Mario, Minesweeper and Target
|
||||
- Fixed an issue with localstorage saving of custom levels
|
||||
|
||||
|
||||
## 29079805
|
||||
|
||||
- combo text on paddle will be grey if we're at the base combo
|
||||
- transparency now rounds up
|
||||
- import level up to 21 x 21
|
||||
- corrected icon of "padding"
|
||||
|
||||
## 29079087
|
||||
|
||||
- measured and improve the performance (test here https://breakout.lecaro.me/?stresstest)
|
||||
- added a few levels
|
||||
- autoplay mode (with wake lock and computer play https://breakout.lecaro.me/?autoplay )
|
||||
- Added particle and sound effect when coin drops below the "waterline" of the puck
|
||||
- slower coins fall once they are under the paddle
|
||||
- in game level editor
|
||||
- allow loading newer save in outdated app (for rollback)
|
||||
- game crashes when reaching level 12 (no level info in runLevels)
|
||||
|
||||
## 29074385
|
||||
|
@ -274,7 +347,7 @@ languages, I may add features again.
|
|||
- cash out : double last level's gains
|
||||
- snowball : Combo resets every 0.1s . +1 combo for each combo gained Since last reset.
|
||||
- Chain reaction : +lvl*lvl combo per brick broken by an explosion, combo resets after explosion is over
|
||||
|
||||
- catching a coin changes the color of the balls
|
||||
- coins stained by balls
|
||||
- fast pause : pause delay divided by {{lvl}} (helps with teleport)
|
||||
- [colin] Capital - les vies non perdues à la fin du niveau rapportent un bonus de points
|
||||
|
@ -296,6 +369,7 @@ languages, I may add features again.
|
|||
- make stats a clairvoyant thing
|
||||
- [colin]P ocket money — bricks absorb coins that touch them, which are released on brick destruction (with a bonus?)
|
||||
- [colin] turn ball gravity on after a top bar hit, and until bouncing on puck
|
||||
- fan : paddle motion creates upward draft that lifts coins and balls
|
||||
|
||||
## Medium difficulty perks ideas
|
||||
- balls collision split them into 4 smaller balls, lvl times (requires rework)
|
||||
|
@ -319,6 +393,8 @@ languages, I may add features again.
|
|||
- accelerometer controls coins and balls
|
||||
- [colin] side pucks - same as above but with two side pucks : hard to know where to put them
|
||||
- [colin] Perk: second puck in the middle of the screen
|
||||
- [colin] Sponge Ball : the ball stores coins it collides with, and releases them when bouncing on any border (left, right, top).
|
||||
|
||||
|
||||
## ideas to sort
|
||||
- wind : move coins based on puck movement not position
|
||||
|
@ -335,6 +411,8 @@ languages, I may add features again.
|
|||
- [colin] plusieurs perks qui déclenchent des effets quand une balle est perdue. par ex: +3 combo à chaque balle perdue, 5 blocs transformés en bombe, balle et coins ralentis, blocs régénérés…
|
||||
- [colin] faster style - augmente le combo en fonction de la vitesse de la balle
|
||||
- [colin] perk: roulette - gagne instantanément 2 perks aléatoires
|
||||
- other block types : bumper (speed up ball) [colin], metal (can't break) [nicolas]
|
||||
- flip perk
|
||||
|
||||
## extra levels
|
||||
|
||||
|
@ -360,6 +438,12 @@ languages, I may add features again.
|
|||
|
||||
## UX / gameplay
|
||||
|
||||
- chill game mode, to just relax your mind :
|
||||
- no 7 levels limit
|
||||
- no upgrades offered at the end of the level
|
||||
- get a random perk
|
||||
- every 7 level it's replaced by another random perk
|
||||
- every 7 levels, +10 base combo and +1 piece
|
||||
- avoid showing a +1 and -1 at the same time when a combo increase is reset
|
||||
- explain to iOS users how to add the app to home screen to get fullscreen
|
||||
- delayed start on mobile to let users place the puck where they want
|
||||
|
@ -370,7 +454,6 @@ languages, I may add features again.
|
|||
## Game engine features ideas
|
||||
- add a clickable button to allow sound to play in chrome android
|
||||
- save state in localstorage for easy resume of a game in progress
|
||||
- ask for permanent storage
|
||||
- handle back bouton in menu
|
||||
- Offline mode web for iphone
|
||||
- controller support on web/mobile
|
||||
|
@ -379,6 +462,7 @@ languages, I may add features again.
|
|||
|
||||
## Maybe one day
|
||||
- https://weblate.org/fr/ quite annoying to have merge conflicts while pushing, i'll enable it later.
|
||||
- auto-detect device performance at first startup and adjust settings accordingly (hard to do in any sort of useful way)
|
||||
- [jaceys] Move the restart button out of the menu, so that it is more easily accessible (will allow user to choose starting perk instead)
|
||||
- colored coins only (coins should be of the color of the ball to count, otherwise what ? i'd rather avoid negative points)
|
||||
- coins avoid ball of different color (pointless)
|
||||
|
@ -473,3 +557,4 @@ Breakout 71 can be installed and work offline in many ways:
|
|||
|
||||
The game should perform well even on low-end devices. It's very lean and does not take much storage space (Roughly 0.1MB). The web version is supposed to work on iOS safari, Firefox ESR and chrome, on desktop and mobile.
|
||||
If the app stutters, turn on "fast mode" in the settings to render a simplified view that should be faster. You can adjust many aspects of the game there, go have a look !
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ android {
|
|||
applicationId = "me.lecaro.breakout"
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 29074738
|
||||
versionName = "29074738"
|
||||
versionCode = 29088680
|
||||
versionName = "29088680"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
|
@ -67,3 +67,6 @@ android {
|
|||
}
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation(libs.androidx.core)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,14 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
File diff suppressed because one or more lines are too long
|
@ -1,11 +1,7 @@
|
|||
package me.lecaro.breakout
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.DownloadManager
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -20,10 +16,12 @@ import android.webkit.ValueCallback
|
|||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import java.io.File
|
||||
import java.net.URLDecoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.jar.Manifest
|
||||
|
||||
const val CHOOSE_FILE_REQUEST_CODE = 548459
|
||||
|
||||
|
@ -50,71 +48,79 @@ class MainActivity : android.app.Activity() {
|
|||
|
||||
private fun downloadFile(url: String) {
|
||||
try {
|
||||
if (!url.startsWith("data:")) {
|
||||
Log.w("DL", "url ignored because it does not start with data:")
|
||||
return
|
||||
}
|
||||
val sdf = SimpleDateFormat("yyyy-M-dd-hh-mm")
|
||||
val currentDate = sdf.format(Date())
|
||||
val base64Data = url.substringAfterLast(',')
|
||||
val decodedBytes = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT)
|
||||
|
||||
if (url.startsWith("data:application/json;base64,")) {
|
||||
writeFile(decodedBytes, "breakout-71-save-$currentDate.json", "application/json")
|
||||
if (url.startsWith("data:application/json;charset=utf-8,")) {
|
||||
|
||||
} else if (url.startsWith("data:video/webm;base64,")) {
|
||||
writeFile(decodedBytes, "breakout-71-gameplay-capture-$currentDate.webm", "video/webm")
|
||||
} else {
|
||||
Log.w("DL", "unexpected type " + url)
|
||||
val urlEncoded = url.substring("data:application/json;charset=utf-8,".length)
|
||||
val str = URLDecoder.decode(urlEncoded, StandardCharsets.UTF_8.name())
|
||||
writeFileAndShare(str.toByteArray(), "breakout-71-save-$currentDate.json", "application/json")
|
||||
}
|
||||
|
||||
if (url.startsWith("data:video/webm;base64,")) {
|
||||
val base64Data = url.substring("data:video/webm;base64,".length)
|
||||
val decodedBytes = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT)
|
||||
writeFileAndShare(decodedBytes, "breakout-71-capture-$currentDate.webm", "video/webm")
|
||||
}
|
||||
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("DL", "Error ${e.message}")
|
||||
Toast.makeText(this, "Error ${e.message}", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFile(decodedBytes:ByteArray,fileName:String, mime:String){
|
||||
fun writeFileAndShare(bytes:ByteArray, fileName: String, mime: String) {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// android 10
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
|
||||
put(MediaStore.Downloads.MIME_TYPE, mime)
|
||||
put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
|
||||
}
|
||||
|
||||
|
||||
val jsonData = String(decodedBytes);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
|
||||
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
|
||||
put(MediaStore.Downloads.MIME_TYPE,mime )
|
||||
put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
|
||||
}
|
||||
|
||||
val uri: Uri? = contentResolver.insert(
|
||||
MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues
|
||||
)
|
||||
uri?.let {
|
||||
contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
outputStream.write(decodedBytes)
|
||||
}
|
||||
}
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
// Example: content://com.google.android.apps.photos.contentprovider/...
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = mime
|
||||
}
|
||||
startActivity(Intent.createChooser(shareIntent, null))
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
val dir = getExternalFilesDir(null)
|
||||
val file = File(dir, fileName)
|
||||
file.writeText(jsonData)
|
||||
Toast.makeText(this, "Saved in $dir", Toast.LENGTH_LONG).show()
|
||||
|
||||
val uri: Uri? = contentResolver.insert(
|
||||
MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues
|
||||
)
|
||||
uri?.let {
|
||||
contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
outputStream.write(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = mime
|
||||
}
|
||||
startActivity(Intent.createChooser(shareIntent, null))
|
||||
|
||||
} else {
|
||||
|
||||
val file = File(getExternalFilesDir(null), fileName)
|
||||
file.writeBytes(bytes)
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this,
|
||||
"$packageName.fileprovider", // Adjust if your authority is different
|
||||
file
|
||||
)
|
||||
|
||||
val shareIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = mime
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
|
||||
startActivity(Intent.createChooser(shareIntent, null))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
@ -155,13 +161,18 @@ class MainActivity : android.app.Activity() {
|
|||
} catch (e: Exception) {
|
||||
Log.e("DL", "Error ${e.message}")
|
||||
Toast.makeText(activity, "Error ${e.message}", Toast.LENGTH_LONG).show()
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
|
||||
Log.d("DL", "url: ${url}")
|
||||
Log.d("DL", "userAgent: ${userAgent}")
|
||||
Log.d("DL", "contentDisposition: ${contentDisposition}")
|
||||
Log.d("DL", "mimetype: ${mimetype}")
|
||||
Log.d("DL", "contentLength: ${contentLength}")
|
||||
|
||||
downloadFile(url)
|
||||
})
|
||||
|
||||
|
|
6
app/src/main/res/xml/file_paths.xml
Normal file
6
app/src/main/res/xml/file_paths.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-files-path
|
||||
name="external_files"
|
||||
path="." />
|
||||
</paths>
|
1713
dist/index.html
vendored
1713
dist/index.html
vendored
File diff suppressed because one or more lines are too long
|
@ -8,6 +8,7 @@ espressoCore = "3.5.1"
|
|||
lifecycleRuntimeKtx = "2.6.1"
|
||||
activityCompose = "1.7.0"
|
||||
composeBom = "2023.08.00"
|
||||
core = "1.13.0"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
|
@ -24,6 +25,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
|||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
androidx-core = { group = "androidx.core", name = "core", version.ref = "core" }
|
||||
|
||||
[plugins]
|
||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// The version of the cache.
|
||||
const VERSION = "29074738";
|
||||
const VERSION = "29088680";
|
||||
|
||||
// The name of the cache
|
||||
const CACHE_NAME = `breakout-71-${VERSION}`;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { GameState, Level, PerkId, Upgrade } from "./types";
|
||||
import { allLevels, icons, upgrades } from "./loadGameData";
|
||||
import { GameState, Level, PerkId, RawLevel, Upgrade } from "./types";
|
||||
import { allLevels, icons, transformRawLevel, upgrades } from "./loadGameData";
|
||||
import { t } from "./i18n/i18n";
|
||||
import { getSettingValue, getTotalScore, setSettingValue } from "./settings";
|
||||
import {
|
||||
|
@ -17,6 +17,7 @@ import {
|
|||
} from "./game_utils";
|
||||
import { getHistory } from "./gameOver";
|
||||
import { noCreative } from "./upgrades";
|
||||
import { levelIconHTML } from "./levelIcon";
|
||||
|
||||
export function creativeMode(gameState: GameState) {
|
||||
return {
|
||||
|
@ -35,22 +36,60 @@ export function creativeMode(gameState: GameState) {
|
|||
|
||||
export async function openCreativeModePerksPicker() {
|
||||
let creativeModePerks: Partial<{ [id in PerkId]: number }> = getSettingValue(
|
||||
"creativeModePerks",
|
||||
{},
|
||||
),
|
||||
choice: Upgrade | Level | "reset" | void;
|
||||
"creativeModePerks",
|
||||
{},
|
||||
);
|
||||
const customLevels = (getSettingValue("custom_levels", []) as RawLevel[]).map(
|
||||
transformRawLevel,
|
||||
);
|
||||
|
||||
while (
|
||||
(choice = await asyncAlert<Upgrade | Level | "reset">({
|
||||
while (true) {
|
||||
const levelOptions = [
|
||||
...allLevels.map((l, li) => {
|
||||
const problem = reasonLevelIsLocked(li, getHistory(), true)?.text || "";
|
||||
return {
|
||||
icon: icons[l.name],
|
||||
text: l.name,
|
||||
value: l,
|
||||
disabled: !!problem,
|
||||
tooltip: problem || describeLevel(l),
|
||||
className: "",
|
||||
};
|
||||
}),
|
||||
...customLevels.map((l) => ({
|
||||
icon: levelIconHTML(l.bricks, l.size, l.color),
|
||||
text: l.name,
|
||||
value: l,
|
||||
disabled: !l.bricks.filter((b) => b !== "_").length,
|
||||
tooltip: describeLevel(l),
|
||||
className: "",
|
||||
})),
|
||||
];
|
||||
|
||||
const selectedLeveOption =
|
||||
levelOptions.find(
|
||||
(l) => l.text === getSettingValue("creativeModeLevel", ""),
|
||||
) || levelOptions[0];
|
||||
selectedLeveOption.className = "highlight";
|
||||
|
||||
const choice = await asyncAlert<Upgrade | Level | "reset" | "play">({
|
||||
title: t("lab.menu_entry"),
|
||||
className: "actionsAsGrid",
|
||||
content: [
|
||||
t("lab.instructions"),
|
||||
{
|
||||
icon: icons["icon:reset"],
|
||||
value: "reset",
|
||||
text: t("lab.reset"),
|
||||
disabled: !sumOfValues(creativeModePerks),
|
||||
},
|
||||
{
|
||||
icon: icons["icon:new_run"],
|
||||
value: "play",
|
||||
text: t("lab.play"),
|
||||
disabled: !sumOfValues(creativeModePerks),
|
||||
},
|
||||
|
||||
t("lab.instructions"),
|
||||
...upgrades
|
||||
.filter((u) => !noCreative.includes(u.id))
|
||||
.map((u) => ({
|
||||
|
@ -62,41 +101,42 @@ export async function openCreativeModePerksPicker() {
|
|||
(u.max + (creativeModePerks.limitless || 0)),
|
||||
value: u,
|
||||
className: creativeModePerks[u.id]
|
||||
? "sandbox"
|
||||
: "sandbox grey-out-unless-hovered",
|
||||
? "sandbox highlight"
|
||||
: "sandbox not-highlighed",
|
||||
tooltip: u.help(creativeModePerks[u.id] || 1),
|
||||
})),
|
||||
t("lab.select_level"),
|
||||
...allLevels.map((l, li) => {
|
||||
const problem =
|
||||
reasonLevelIsLocked(li, getHistory(), true)?.text || "";
|
||||
return {
|
||||
icon: icons[l.name],
|
||||
text: l.name,
|
||||
value: l,
|
||||
disabled: !!problem,
|
||||
tooltip: problem || describeLevel(l),
|
||||
};
|
||||
}),
|
||||
...levelOptions,
|
||||
],
|
||||
}))
|
||||
) {
|
||||
});
|
||||
if (!choice) return;
|
||||
if (choice === "reset") {
|
||||
upgrades.forEach((u) => {
|
||||
creativeModePerks[u.id] = 0;
|
||||
});
|
||||
} else if ("bricks" in choice) {
|
||||
setSettingValue("creativeModePerks", creativeModePerks);
|
||||
setSettingValue("creativeModeLevel", "");
|
||||
} else if (
|
||||
choice === "play" ||
|
||||
("bricks" in choice &&
|
||||
choice.name == getSettingValue("creativeModeLevel", ""))
|
||||
) {
|
||||
if (await confirmRestart(gameState)) {
|
||||
restart({ perks: creativeModePerks, level: choice.name });
|
||||
restart({
|
||||
perks: creativeModePerks,
|
||||
level: selectedLeveOption.value,
|
||||
isCreativeRun: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} else if ("bricks" in choice) {
|
||||
setSettingValue("creativeModeLevel", choice.name);
|
||||
} else if (choice) {
|
||||
creativeModePerks[choice.id] =
|
||||
((creativeModePerks[choice.id] || 0) + 1) %
|
||||
(choice.max + 1 + (creativeModePerks.limitless || 0));
|
||||
} else {
|
||||
return;
|
||||
|
||||
setSettingValue("creativeModePerks", creativeModePerks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1 +1 @@
|
|||
"29074738"
|
||||
"29088680"
|
||||
|
|
154
src/game.less
154
src/game.less
|
@ -8,6 +8,8 @@
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@purple: #6262ea;
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -70,8 +72,9 @@ canvas:not(#game) {
|
|||
color: gold;
|
||||
transition: color 0.01s;
|
||||
}
|
||||
&.hidden {
|
||||
display: none;
|
||||
|
||||
&.computer_controlled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
span {
|
||||
|
@ -106,7 +109,7 @@ body:not(.has-alert-open) #popup {
|
|||
|
||||
#popup {
|
||||
&::before {
|
||||
z-index: 10;
|
||||
z-index: 4;
|
||||
content: "";
|
||||
display: block;
|
||||
position: fixed;
|
||||
|
@ -118,7 +121,7 @@ body:not(.has-alert-open) #popup {
|
|||
overflow: auto;
|
||||
|
||||
& > div {
|
||||
z-index: 11;
|
||||
z-index: 5;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
padding: 20px 10px;
|
||||
|
@ -191,6 +194,9 @@ body:not(.has-alert-open) #popup {
|
|||
}
|
||||
}
|
||||
|
||||
&.actionsAsGrid.large > div > section {
|
||||
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
||||
}
|
||||
&.actionsAsGrid > div {
|
||||
max-width: none;
|
||||
|
||||
|
@ -221,7 +227,7 @@ body:not(.has-alert-open) #popup {
|
|||
border: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
z-index: 12;
|
||||
z-index: 6;
|
||||
|
||||
&:before {
|
||||
content: "+";
|
||||
|
@ -266,45 +272,6 @@ body:not(.has-alert-open) #popup {
|
|||
}
|
||||
}
|
||||
|
||||
/*Unlocks progress bar*/
|
||||
.progress {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
background: #1c1c2f;
|
||||
color: #fff;
|
||||
box-shadow: inset 3px 3px 5px rgba(0, 0, 0, 0.5);
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
& > .progress_bar_part {
|
||||
display: block;
|
||||
background: #4049ca;
|
||||
box-shadow: inset 3px 3px 5px rgba(0, 0, 0, 0.5);
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transform-origin: top left;
|
||||
animation: grow 1s both ease-out;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
& > span {
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@keyframes grow {
|
||||
0% {
|
||||
transform: scale(0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#level-recording-container {
|
||||
max-width: 400px;
|
||||
text-align: center;
|
||||
|
@ -459,7 +426,7 @@ h2.histogram-title strong {
|
|||
background: black;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
z-index: 11;
|
||||
z-index: 5;
|
||||
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
|
@ -477,6 +444,7 @@ h2.histogram-title strong {
|
|||
cursor: pointer;
|
||||
background: black;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0 5px;
|
||||
|
@ -488,11 +456,13 @@ h2.histogram-title strong {
|
|||
td:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
tr:nth-child(2n) {
|
||||
background: rgba(0, 0, 0, 0.58);
|
||||
}
|
||||
|
@ -508,6 +478,7 @@ h2.histogram-title strong {
|
|||
height: 7px;
|
||||
bottom: 2px;
|
||||
border-radius: 2px;
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
inset: 1px;
|
||||
|
@ -529,18 +500,95 @@ h2.histogram-title strong {
|
|||
border-radius: 2px;
|
||||
padding-right: 10px;
|
||||
pointer-events: none;
|
||||
animation: toast forwards;
|
||||
}
|
||||
|
||||
@keyframes toast {
|
||||
0%,
|
||||
100% {
|
||||
transition:
|
||||
opacity 200ms,
|
||||
transform 200ms;
|
||||
z-index: 7;
|
||||
&.hidden {
|
||||
opacity: 0;
|
||||
transform: translate(-20px, -20px) scale(0.5);
|
||||
}
|
||||
10%,
|
||||
90% {
|
||||
&.visible {
|
||||
opacity: 0.8;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.gridEdit > div > span,
|
||||
.palette > span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 1px solid;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
border-color: gold;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
box-shadow: inset 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
.gridEdit {
|
||||
& > div {
|
||||
display: flex;
|
||||
|
||||
& > span {
|
||||
width: calc(min(500px, 100vw, 100vh - 200px) / var(--grid-size));
|
||||
height: calc(min(500px, 100vw, 100vh - 200px) / var(--grid-size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.palette {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
& > span {
|
||||
&[data-selected="true"] {
|
||||
border: 2px solid white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#stats {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
width: 100vw;
|
||||
max-width: 400px;
|
||||
color: white;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
opacity: 1;
|
||||
& > div {
|
||||
background: rgba(38, 38, 38, 0.5);
|
||||
position: relative;
|
||||
> div {
|
||||
background: @purple;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
transform-origin: top left;
|
||||
}
|
||||
> strong {
|
||||
position: relative;
|
||||
padding: 0 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.highlight {
|
||||
position: relative;
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(-45deg, @purple, transparent);
|
||||
mix-blend-mode: screen;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
.not-highlighed {
|
||||
opacity: 0.8;
|
||||
color: #8a8a8a;
|
||||
}
|
||||
|
|
294
src/game.ts
294
src/game.ts
|
@ -1,4 +1,10 @@
|
|||
import { allLevels, appVersion, icons, upgrades } from "./loadGameData";
|
||||
import {
|
||||
allLevels,
|
||||
allLevelsAndIcons,
|
||||
appVersion,
|
||||
icons,
|
||||
upgrades,
|
||||
} from "./loadGameData";
|
||||
import {
|
||||
Ball,
|
||||
Coin,
|
||||
|
@ -17,18 +23,20 @@ import {
|
|||
describeLevel,
|
||||
getRowColIndex,
|
||||
highScoreText,
|
||||
hoursSpentPlaying,
|
||||
levelsListHTMl,
|
||||
max_levels,
|
||||
pickedUpgradesHTMl,
|
||||
reasonLevelIsLocked,
|
||||
sample,
|
||||
sumOfValues,
|
||||
} from "./game_utils";
|
||||
|
||||
import "./PWA/sw_loader";
|
||||
import { getCurrentLang, languages, t } from "./i18n/i18n";
|
||||
import {
|
||||
commitSettingsChangesToLocalStorage,
|
||||
cycleMaxCoins,
|
||||
cycleMaxParticles,
|
||||
getCurrentMaxCoins,
|
||||
getCurrentMaxParticles,
|
||||
getSettingValue,
|
||||
|
@ -38,6 +46,7 @@ import {
|
|||
import {
|
||||
forEachLiveOne,
|
||||
gameStateTick,
|
||||
liveCount,
|
||||
normalizeGameState,
|
||||
pickRandomUpgrades,
|
||||
setLevel,
|
||||
|
@ -46,8 +55,8 @@ import {
|
|||
import {
|
||||
backgroundCanvas,
|
||||
gameCanvas,
|
||||
getHaloScale,
|
||||
haloCanvas,
|
||||
haloScale,
|
||||
render,
|
||||
scoreDisplay,
|
||||
} from "./render";
|
||||
|
@ -66,12 +75,10 @@ import {
|
|||
requiredAsyncAlert,
|
||||
} from "./asyncAlert";
|
||||
import { isOptionOn, options, toggleOption } from "./options";
|
||||
import { hashCode } from "./getLevelBackground";
|
||||
import {
|
||||
catchRateBest,
|
||||
catchRateGood,
|
||||
clamp,
|
||||
hoursSpentPlaying,
|
||||
levelTimeBest,
|
||||
levelTimeGood,
|
||||
missesBest,
|
||||
|
@ -89,6 +96,7 @@ import { generateSaveFileContent } from "./generateSaveFileContent";
|
|||
import { runHistoryViewerMenuEntry } from "./runHistoryViewer";
|
||||
import { getNearestUnlockHTML, openScorePanel } from "./openScorePanel";
|
||||
import { monitorLevelsUnlocks } from "./monitorLevelsUnlocks";
|
||||
import { levelEditorMenuEntry } from "./levelEditor";
|
||||
|
||||
export async function play() {
|
||||
if (await applyFullScreenChoice()) return;
|
||||
|
@ -105,7 +113,12 @@ export async function play() {
|
|||
export function pause(playerAskedForPause: boolean) {
|
||||
if (!gameState.running) return;
|
||||
if (gameState.pauseTimeout) return;
|
||||
if (gameState.computer_controlled) return;
|
||||
if (gameState.startParams.computer_controlled) {
|
||||
if (gameState.startParams?.computer_controlled) {
|
||||
play();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const stop = () => {
|
||||
gameState.running = false;
|
||||
|
@ -152,6 +165,7 @@ export const fitSize = (gameState: GameState) => {
|
|||
gameCanvas.height = height;
|
||||
backgroundCanvas.width = width;
|
||||
backgroundCanvas.height = height;
|
||||
const haloScale = getHaloScale();
|
||||
haloCanvas.width = width / haloScale;
|
||||
haloCanvas.height = height / haloScale;
|
||||
|
||||
|
@ -416,12 +430,12 @@ export function hitsSomething(x: number, y: number, radius: number) {
|
|||
}
|
||||
|
||||
export function tick() {
|
||||
startWork("physics");
|
||||
const currentTick = performance.now();
|
||||
const timeDeltaMs = currentTick - gameState.lastTick;
|
||||
gameState.lastTick = currentTick;
|
||||
|
||||
let frames = Math.min(4, timeDeltaMs / (1000 / 60));
|
||||
|
||||
if (gameState.keyboardPuckSpeed) {
|
||||
setMousePos(
|
||||
gameState,
|
||||
|
@ -435,34 +449,88 @@ export function tick() {
|
|||
1,
|
||||
);
|
||||
}
|
||||
normalizeGameState(gameState);
|
||||
|
||||
normalizeGameState(gameState);
|
||||
if (gameState.running) {
|
||||
gameState.levelTime += timeDeltaMs * frames;
|
||||
gameState.runStatistics.runTime += timeDeltaMs * frames;
|
||||
gameStateTick(gameState, frames);
|
||||
const maxBallSpeed =
|
||||
Math.sqrt(
|
||||
Math.max(0, ...gameState.balls.map(({ vx, vy }) => vx * vx + vy * vy)),
|
||||
) * frames;
|
||||
const steps = Math.ceil(maxBallSpeed / 8);
|
||||
for (let i = 0; i < steps; i++) gameStateTick(gameState, frames / steps);
|
||||
}
|
||||
|
||||
if (gameState.running || gameState.needsRender) {
|
||||
gameState.needsRender = false;
|
||||
render(gameState);
|
||||
}
|
||||
startWork("record video");
|
||||
if (gameState.running) {
|
||||
recordOneFrame(gameState);
|
||||
}
|
||||
startWork("sound");
|
||||
if (isOptionOn("sound")) {
|
||||
playPendingSounds(gameState);
|
||||
}
|
||||
startWork("idle");
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
FPSCounter++;
|
||||
}
|
||||
|
||||
const stats = document.getElementById("stats") as HTMLDivElement;
|
||||
let total = {};
|
||||
let lastTick = performance.now();
|
||||
let doing = "idle";
|
||||
let FPSCounter = 0;
|
||||
export let lastMeasuredFPS = 60;
|
||||
|
||||
export function startWork(what) {
|
||||
if (!gameState.startParams.stress) return;
|
||||
const newNow = performance.now();
|
||||
if (doing) {
|
||||
total[doing] = (total[doing] || 0) + (newNow - lastTick);
|
||||
}
|
||||
lastTick = newNow;
|
||||
doing = what;
|
||||
}
|
||||
setInterval(() => {
|
||||
lastMeasuredFPS = FPSCounter;
|
||||
FPSCounter = 0;
|
||||
|
||||
if (!gameState.startParams.stress) {
|
||||
stats.style.display = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
stats.style.display = "block";
|
||||
const totalTime = sumOfValues(total);
|
||||
stats.innerHTML =
|
||||
`
|
||||
<div>
|
||||
${lastMeasuredFPS} FPS -
|
||||
${liveCount(gameState.coins)} / ${getCurrentMaxCoins()} Coins -
|
||||
${liveCount(gameState.particles) + liveCount(gameState.lights) + liveCount(gameState.texts)} / ${getCurrentMaxParticles() * 3} particles
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
` +
|
||||
Object.entries(total)
|
||||
// .sort((a, b) => b[1] - a[1])
|
||||
.map(
|
||||
(t) =>
|
||||
` <div>
|
||||
<div style="transform: scale(${clamp(t[1] / totalTime, 0, 1)},1)"></div>
|
||||
<strong>${t[0]} : ${Math.floor(t[1])} ms</strong>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
total = {};
|
||||
}, 1000);
|
||||
|
||||
setInterval(() => {
|
||||
|
@ -518,12 +586,21 @@ export async function openMainMenu() {
|
|||
},
|
||||
creativeMode(gameState),
|
||||
runHistoryViewerMenuEntry(),
|
||||
levelEditorMenuEntry(),
|
||||
{
|
||||
icon: icons["icon:unlocks"],
|
||||
text: t("main_menu.unlocks"),
|
||||
icon: icons["icon:unlocked_upgrades"],
|
||||
text: t("unlocks.upgrades"),
|
||||
help: t("main_menu.unlocks_help"),
|
||||
value() {
|
||||
openUnlocksList();
|
||||
openUnlockedUpgradesList();
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: icons["icon:unlocked_levels"],
|
||||
text: t("unlocks.levels"),
|
||||
help: t("main_menu.unlocks_help"),
|
||||
value() {
|
||||
openUnlockedLevelsList();
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -608,18 +685,30 @@ async function openSettingsMenu() {
|
|||
(await confirmRestart(gameState))
|
||||
) {
|
||||
setSettingValue("lang", pick);
|
||||
commitSettingsChangesToLocalStorage();
|
||||
window.location.reload();
|
||||
}
|
||||
},
|
||||
});
|
||||
for (const key of Object.keys(options) as OptionId[]) {
|
||||
if (options[key])
|
||||
if (options[key]) {
|
||||
actions.push({
|
||||
icon: isOptionOn(key)
|
||||
? icons["icon:checkmark_checked"]
|
||||
: icons["icon:checkmark_unchecked"],
|
||||
text: options[key].name,
|
||||
help: options[key].help,
|
||||
disabled:
|
||||
(isOptionOn("basic") &&
|
||||
[
|
||||
"extra_bright",
|
||||
"contrast",
|
||||
"smooth_lighting",
|
||||
"precise_lighting",
|
||||
"probabilistic_lighting",
|
||||
].includes(key)) ||
|
||||
// (isInWebView && key == "record") ||
|
||||
false,
|
||||
value: () => {
|
||||
toggleOption(key);
|
||||
fitSize(gameState);
|
||||
|
@ -627,30 +716,23 @@ async function openSettingsMenu() {
|
|||
openSettingsMenu();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
actions.push({
|
||||
icon: icons["icon:download"],
|
||||
text: t("settings.download_save_file"),
|
||||
help: t("settings.download_save_file_help"),
|
||||
async value() {
|
||||
const signedPayload = generateSaveFileContent();
|
||||
|
||||
const dlLink = document.createElement("a");
|
||||
|
||||
const obj = {
|
||||
fileType: "B71-save-file",
|
||||
appVersion,
|
||||
payload: generateSaveFileContent(),
|
||||
};
|
||||
const json = JSON.stringify(obj, null, 2);
|
||||
dlLink.setAttribute(
|
||||
"href",
|
||||
"data:application/json;base64," +
|
||||
btoa(
|
||||
JSON.stringify({
|
||||
fileType: "B71-save-file",
|
||||
appVersion,
|
||||
signedPayload,
|
||||
key: hashCode(
|
||||
"Security by obscurity, but really the game is oss so eh" +
|
||||
signedPayload,
|
||||
),
|
||||
}),
|
||||
),
|
||||
"data:application/json;charset=utf-8," + encodeURIComponent(json),
|
||||
);
|
||||
|
||||
dlLink.setAttribute(
|
||||
|
@ -660,7 +742,7 @@ async function openSettingsMenu() {
|
|||
.toISOString()
|
||||
.slice(0, 19)
|
||||
.replace(/[^0-9]+/gi, "-") +
|
||||
".b71",
|
||||
".json",
|
||||
);
|
||||
document.body.appendChild(dlLink);
|
||||
dlLink.click();
|
||||
|
@ -697,35 +779,21 @@ async function openSettingsMenu() {
|
|||
|
||||
reader.readAsText(file);
|
||||
});
|
||||
const {
|
||||
fileType,
|
||||
appVersion: fileVersion,
|
||||
signedPayload,
|
||||
key,
|
||||
} = JSON.parse(content);
|
||||
const { fileType, signedPayload, payload } = JSON.parse(content);
|
||||
if (fileType !== "B71-save-file")
|
||||
throw new Error("Not a B71 save file");
|
||||
if (fileVersion > appVersion)
|
||||
throw new Error(
|
||||
"Please update your app first, this file is for version " +
|
||||
fileVersion +
|
||||
" or newer.",
|
||||
);
|
||||
|
||||
if (
|
||||
key !==
|
||||
hashCode(
|
||||
"Security by obscurity, but really the game is oss so eh" +
|
||||
signedPayload,
|
||||
)
|
||||
) {
|
||||
throw new Error("Key does not match content.");
|
||||
}
|
||||
|
||||
const localStorageContent = JSON.parse(signedPayload);
|
||||
localStorage.clear();
|
||||
for (let key in localStorageContent) {
|
||||
localStorage.setItem(key, localStorageContent[key]);
|
||||
if (payload) {
|
||||
localStorage.clear();
|
||||
for (let key in payload) {
|
||||
localStorage.setItem(key, JSON.stringify(payload[key]));
|
||||
}
|
||||
} else if (signedPayload) {
|
||||
// Old file format
|
||||
const localStorageContent = JSON.parse(signedPayload);
|
||||
localStorage.clear();
|
||||
for (let key in localStorageContent) {
|
||||
localStorage.setItem(key, localStorageContent[key]);
|
||||
}
|
||||
}
|
||||
await asyncAlert({
|
||||
title: t("settings.save_file_loaded"),
|
||||
|
@ -759,15 +827,6 @@ async function openSettingsMenu() {
|
|||
await openSettingsMenu();
|
||||
},
|
||||
});
|
||||
actions.push({
|
||||
icon: icons["icon:particles"],
|
||||
text: t("settings.max_particles", { max: getCurrentMaxParticles() }),
|
||||
help: t("settings.max_particles_help"),
|
||||
async value() {
|
||||
cycleMaxParticles();
|
||||
await openSettingsMenu();
|
||||
},
|
||||
});
|
||||
|
||||
actions.push({
|
||||
icon: icons["icon:reset"],
|
||||
|
@ -796,6 +855,20 @@ async function openSettingsMenu() {
|
|||
}
|
||||
},
|
||||
});
|
||||
actions.push({
|
||||
text: t("settings.autoplay"),
|
||||
help: t("settings.autoplay_help"),
|
||||
async value() {
|
||||
startComputerControlledGame(false);
|
||||
},
|
||||
});
|
||||
actions.push({
|
||||
text: t("settings.stress_test"),
|
||||
help: t("settings.stress_test_help"),
|
||||
async value() {
|
||||
startComputerControlledGame(true);
|
||||
},
|
||||
});
|
||||
|
||||
const cb = await asyncAlert<() => void>({
|
||||
title: t("main_menu.settings_title"),
|
||||
|
@ -839,16 +912,18 @@ async function applyFullScreenChoice() {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function openUnlocksList() {
|
||||
async function openUnlockedUpgradesList() {
|
||||
const ts = getTotalScore();
|
||||
const hintField = isOptionOn("mobile-mode") ? "help" : "tooltip";
|
||||
|
||||
const upgradeActions = upgrades
|
||||
.sort((a, b) => a.threshold - b.threshold)
|
||||
.map(({ name, id, threshold, icon, help }) => ({
|
||||
text: name,
|
||||
disabled: ts < threshold,
|
||||
value: { perks: { [id]: 1 }, level: "icon:" + id } as RunParams,
|
||||
value: {
|
||||
perks: { [id]: 1 },
|
||||
level: allLevelsAndIcons.find((l) => l.name === "icon:" + id),
|
||||
} as RunParams,
|
||||
icon,
|
||||
[hintField]:
|
||||
ts < threshold
|
||||
|
@ -856,6 +931,29 @@ async function openUnlocksList() {
|
|||
: help(1),
|
||||
}));
|
||||
|
||||
const tryOn = await asyncAlert<RunParams>({
|
||||
title: t("unlocks.title_upgrades", {
|
||||
unlocked: upgradeActions.filter((a) => !a.disabled).length,
|
||||
out_of: upgradeActions.length,
|
||||
}),
|
||||
content: [
|
||||
`<p>${t("unlocks.intro", { ts })}
|
||||
${upgradeActions.find((u) => u.disabled) ? t("unlocks.greyed_out_help") : ""}</p> `,
|
||||
...upgradeActions,
|
||||
],
|
||||
allowClose: true,
|
||||
className: "actionsAsGrid large",
|
||||
});
|
||||
if (tryOn) {
|
||||
if (await confirmRestart(gameState)) {
|
||||
restart({ ...tryOn });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function openUnlockedLevelsList() {
|
||||
const hintField = isOptionOn("mobile-mode") ? "help" : "tooltip";
|
||||
|
||||
const unlockedBefore = new Set(
|
||||
getSettingValue("breakout_71_unlocked_levels", []),
|
||||
);
|
||||
|
@ -870,29 +968,20 @@ async function openUnlocksList() {
|
|||
return {
|
||||
text: l.name + percentUnlocked,
|
||||
disabled: !!lockedBecause,
|
||||
value: { level: l.name } as RunParams,
|
||||
value: { level: l } as RunParams,
|
||||
icon: icons[l.name],
|
||||
[hintField]: lockedBecause?.text || describeLevel(l),
|
||||
};
|
||||
});
|
||||
|
||||
const tryOn = await asyncAlert<RunParams>({
|
||||
title: t("unlocks.title_upgrades", {
|
||||
unlocked: upgradeActions.filter((a) => !a.disabled).length,
|
||||
out_of: upgradeActions.length,
|
||||
title: t("unlocks.level", {
|
||||
unlocked: levelActions.filter((a) => !a.disabled).length,
|
||||
out_of: levelActions.length,
|
||||
}),
|
||||
content: [
|
||||
`<p>${t("unlocks.intro", { ts })}
|
||||
${upgradeActions.find((u) => u.disabled) ? t("unlocks.greyed_out_help") : ""}</p> `,
|
||||
...upgradeActions,
|
||||
t("unlocks.level", {
|
||||
unlocked: levelActions.filter((a) => !a.disabled).length,
|
||||
out_of: levelActions.length,
|
||||
}),
|
||||
...levelActions,
|
||||
],
|
||||
content: [...levelActions],
|
||||
allowClose: true,
|
||||
className: isOptionOn("mobile-mode") ? "" : "actionsAsGrid",
|
||||
className: "actionsAsGrid large",
|
||||
});
|
||||
if (tryOn) {
|
||||
if (await confirmRestart(gameState)) {
|
||||
|
@ -983,8 +1072,8 @@ document.addEventListener("keyup", async (e) => {
|
|||
!alertsOpen &&
|
||||
pageLoad < Date.now() - 500
|
||||
) {
|
||||
if (gameState.computer_controlled) {
|
||||
return startComputerControlledGame();
|
||||
if (gameState.startParams.computer_controlled) {
|
||||
return startComputerControlledGame(gameState.startParams.stress);
|
||||
}
|
||||
// When doing ctrl + R in dev to refresh, i don't want to instantly restart a run
|
||||
if (await confirmRestart(gameState)) {
|
||||
|
@ -1004,30 +1093,43 @@ export function restart(params: RunParams) {
|
|||
Object.assign(gameState, newGameState(params));
|
||||
// Recompute brick size according to level
|
||||
fitSize(gameState);
|
||||
|
||||
pauseRecording();
|
||||
setLevel(gameState, 0);
|
||||
if (params?.computer_controlled) {
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
if (window.location.search.includes("autoplay")) {
|
||||
startComputerControlledGame();
|
||||
if (window.location.search.match(/autoplay|stress/)) {
|
||||
startComputerControlledGame(window.location.search.includes("stress"));
|
||||
} else {
|
||||
restart({});
|
||||
}
|
||||
|
||||
export function startComputerControlledGame() {
|
||||
const perks: Partial<PerksMap> = { base_combo: 7, pierce: 3 };
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const u = sample(upgrades);
|
||||
perks[u.id] = Math.floor(Math.random() * u.max) + 1;
|
||||
export function startComputerControlledGame(stress: boolean = false) {
|
||||
const perks: Partial<PerksMap> = { base_combo: 20, pierce: 3 };
|
||||
if (stress) {
|
||||
Object.assign(perks, {
|
||||
base_combo: 5000,
|
||||
pierce: 20,
|
||||
rainbow: 3,
|
||||
sapper: 2,
|
||||
etherealcoins: 1,
|
||||
bricks_attract_ball: 1,
|
||||
respawn: 3,
|
||||
});
|
||||
} else {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const u = sample(upgrades);
|
||||
perks[u.id] ||= Math.floor(Math.random() * u.max) + 1;
|
||||
}
|
||||
perks.superhot = 0;
|
||||
}
|
||||
perks.superhot = 0;
|
||||
restart({
|
||||
level: sample(allLevels)?.name,
|
||||
level: sample(allLevels.filter((l) => l.color === "#000000")),
|
||||
computer_controlled: true,
|
||||
perks,
|
||||
stress,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,36 +5,51 @@ import { gameState, pause, restart } from "./game";
|
|||
import {
|
||||
currentLevelInfo,
|
||||
describeLevel,
|
||||
findLast,
|
||||
pickedUpgradesHTMl,
|
||||
reasonLevelIsLocked,
|
||||
} from "./game_utils";
|
||||
import { getTotalScore } from "./settings";
|
||||
import {
|
||||
askForPersistentStorage,
|
||||
getSettingValue,
|
||||
getTotalScore,
|
||||
setSettingValue,
|
||||
} from "./settings";
|
||||
import { stopRecording } from "./recording";
|
||||
import { asyncAlert } from "./asyncAlert";
|
||||
import { rawUpgrades } from "./upgrades";
|
||||
import { run } from "jest";
|
||||
import { editRawLevelList } from "./levelEditor";
|
||||
import { openCreativeModePerksPicker } from "./creative";
|
||||
|
||||
export function addToTotalPlayTime(ms: number) {
|
||||
try {
|
||||
localStorage.setItem(
|
||||
"breakout_71_total_play_time",
|
||||
JSON.stringify(
|
||||
JSON.parse(localStorage.getItem("breakout_71_total_play_time") || "0") +
|
||||
ms,
|
||||
),
|
||||
);
|
||||
} catch (e) {}
|
||||
setSettingValue(
|
||||
"breakout_71_total_play_time",
|
||||
getSettingValue("breakout_71_total_play_time", 0) + ms,
|
||||
);
|
||||
}
|
||||
|
||||
export function gameOver(title: string, intro: string) {
|
||||
if (!gameState.running) return;
|
||||
if (gameState.isGameOver) return;
|
||||
|
||||
gameState.isGameOver = true;
|
||||
pause(true);
|
||||
askForPersistentStorage();
|
||||
stopRecording();
|
||||
addToTotalPlayTime(gameState.runStatistics.runTime);
|
||||
|
||||
if (typeof gameState.startParams.isEditorTrialRun === "number") {
|
||||
editRawLevelList(gameState.startParams.isEditorTrialRun);
|
||||
restart({});
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameState.startParams.isCreativeRun) {
|
||||
openCreativeModePerksPicker();
|
||||
restart({});
|
||||
return;
|
||||
}
|
||||
|
||||
// unlocks
|
||||
const endTs = getTotalScore();
|
||||
const startTs = endTs - gameState.score;
|
||||
|
@ -82,6 +97,8 @@ export function gameOver(title: string, intro: string) {
|
|||
help: "",
|
||||
},
|
||||
`<div id="level-recording-container"></div>`,
|
||||
|
||||
pickedUpgradesHTMl(gameState),
|
||||
unlocksInfo,
|
||||
getHistograms(gameState),
|
||||
],
|
||||
|
|
|
@ -12,13 +12,14 @@ import {
|
|||
} from "./types";
|
||||
|
||||
import {
|
||||
ballTransparency,
|
||||
brickCenterX,
|
||||
brickCenterY,
|
||||
currentLevelInfo,
|
||||
distance2,
|
||||
distanceBetween,
|
||||
getClosestBall,
|
||||
getCoinRenderColor,
|
||||
getCornerOffset,
|
||||
getMajorityValue,
|
||||
getPossibleUpgrades,
|
||||
getRowColIndex,
|
||||
|
@ -48,12 +49,17 @@ import {
|
|||
} from "./game";
|
||||
import { stopRecording } from "./recording";
|
||||
import { isOptionOn } from "./options";
|
||||
import { clamp, comboKeepingRate } from "./pure_functions";
|
||||
import {
|
||||
ballTransparency,
|
||||
clamp,
|
||||
coinsBoostedCombo,
|
||||
comboKeepingRate,
|
||||
} from "./pure_functions";
|
||||
import { addToTotalScore } from "./addToTotalScore";
|
||||
import { hashCode } from "./getLevelBackground";
|
||||
|
||||
export function setMousePos(gameState: GameState, x: number) {
|
||||
if (gameState.computer_controlled) return;
|
||||
if (gameState.startParams.computer_controlled) return;
|
||||
gameState.puckPosition = x;
|
||||
|
||||
// Sets the puck position, and updates the ball position if they are supposed to follow it
|
||||
|
@ -105,7 +111,7 @@ function computerControl(gameState: GameState) {
|
|||
10,
|
||||
);
|
||||
if (gameState.levelTime > 30000) {
|
||||
startComputerControlledGame();
|
||||
startComputerControlledGame(gameState.startParams.stress);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,6 +143,7 @@ export function resetBalls(gameState: GameState) {
|
|||
piercePoints: gameState.perks.pierce * 3,
|
||||
hitSinceBounce: 0,
|
||||
brokenSinceBounce: 0,
|
||||
sidesHitsSinceBounce: 0,
|
||||
sapperUses: 0,
|
||||
});
|
||||
}
|
||||
|
@ -158,6 +165,7 @@ export function putBallsAtPuck(gameState: GameState) {
|
|||
ball.previousY = ball.y;
|
||||
ball.hitSinceBounce = 0;
|
||||
ball.brokenSinceBounce = 0;
|
||||
ball.sidesHitsSinceBounce = 0;
|
||||
ball.piercePoints = gameState.perks.pierce * 3;
|
||||
});
|
||||
}
|
||||
|
@ -182,11 +190,7 @@ export function normalizeGameState(gameState: GameState) {
|
|||
),
|
||||
);
|
||||
|
||||
const corner =
|
||||
(gameState.levelTime
|
||||
? gameState.perks.corner_shot * gameState.puckWidth
|
||||
: 0) -
|
||||
gameState.perks.unbounded * gameState.brickWidth;
|
||||
const corner = getCornerOffset(gameState);
|
||||
|
||||
let minX = gameState.offsetXRoundedDown + gameState.puckWidth / 2 - corner;
|
||||
|
||||
|
@ -216,12 +220,7 @@ export function baseCombo(gameState: GameState) {
|
|||
gameState.perks.minefield &&
|
||||
gameState.bricks.filter((b) => b === "black").length *
|
||||
gameState.perks.minefield;
|
||||
return (
|
||||
1 +
|
||||
gameState.perks.base_combo * 3 +
|
||||
gameState.perks.smaller_puck * 5 +
|
||||
mineFieldBonus
|
||||
);
|
||||
return 1 + gameState.perks.base_combo * 3 + mineFieldBonus;
|
||||
}
|
||||
|
||||
export function resetCombo(
|
||||
|
@ -232,6 +231,13 @@ export function resetCombo(
|
|||
const prev = gameState.combo;
|
||||
gameState.combo = baseCombo(gameState);
|
||||
|
||||
if (gameState.perks.double_or_nothing) {
|
||||
gameState.score = Math.floor(
|
||||
gameState.score * clamp(1 - gameState.perks.double_or_nothing / 10, 0, 1),
|
||||
);
|
||||
schedulGameSound(gameState, "lifeLost", x, 1);
|
||||
}
|
||||
|
||||
if (prev > gameState.combo && gameState.perks.soft_reset) {
|
||||
gameState.combo += Math.floor(
|
||||
(prev - gameState.combo) * comboKeepingRate(gameState.perks.soft_reset),
|
||||
|
@ -269,6 +275,7 @@ export function increaseCombo(
|
|||
if (by <= 0) {
|
||||
return;
|
||||
}
|
||||
by *= 1 + gameState.perks.double_or_nothing;
|
||||
gameState.combo += by;
|
||||
if (
|
||||
isOptionOn("comboIncreaseTexts") &&
|
||||
|
@ -385,7 +392,7 @@ export function explosionAt(
|
|||
c.vx += (((dx / d2) * 10 * size) / c.weight) * factor;
|
||||
c.vy += (((dy / d2) * 10 * size) / c.weight) * factor;
|
||||
});
|
||||
gameState.lastExplosion = Date.now();
|
||||
gameState.lastExplosion = gameState.levelTime;
|
||||
|
||||
if (gameState.perks.implosions) {
|
||||
spawnImplosion(gameState, 7 * size, x, y, "#FFFFFF");
|
||||
|
@ -396,6 +403,7 @@ export function explosionAt(
|
|||
gameState.runStatistics.bricks_broken++;
|
||||
|
||||
if (gameState.perks.zen) {
|
||||
gameState.lastZenComboIncrease = gameState.levelTime;
|
||||
resetCombo(gameState, x, y);
|
||||
}
|
||||
}
|
||||
|
@ -419,10 +427,6 @@ export function explodeBrick(
|
|||
const x = brickCenterX(gameState, index),
|
||||
y = brickCenterY(gameState, index);
|
||||
|
||||
// if (color === "transparent") {
|
||||
// schedulGameSound(gameState, "void", x, 1);
|
||||
// resetCombo(gameState, x, y);
|
||||
// }
|
||||
setBrick(gameState, index, "");
|
||||
explosionAt(gameState, index, x, y, ball, 0);
|
||||
if (gameState.perks.minefield) {
|
||||
|
@ -437,35 +441,17 @@ export function explodeBrick(
|
|||
|
||||
setBrick(gameState, index, "");
|
||||
|
||||
let coinsToSpawn = gameState.combo;
|
||||
if (gameState.lastCombo > coinsToSpawn) {
|
||||
// In case a reset happens in the same frame as a spawn, i want the combo to stay high (for minefield and zen in particular)
|
||||
coinsToSpawn = gameState.lastCombo;
|
||||
}
|
||||
if (gameState.perks.sturdy_bricks) {
|
||||
// +10% per level
|
||||
coinsToSpawn += Math.ceil(
|
||||
((2 + gameState.perks.sturdy_bricks) / 2) * coinsToSpawn,
|
||||
);
|
||||
}
|
||||
if (gameState.perks.transparency) {
|
||||
coinsToSpawn = Math.round(
|
||||
coinsToSpawn *
|
||||
(1 +
|
||||
(ballTransparency(ball, gameState) * gameState.perks.transparency) /
|
||||
2),
|
||||
);
|
||||
}
|
||||
let coinsToSpawn = coinsBoostedCombo(gameState);
|
||||
|
||||
gameState.levelSpawnedCoins += coinsToSpawn;
|
||||
gameState.runStatistics.coins_spawned += coinsToSpawn;
|
||||
gameState.runStatistics.bricks_broken++;
|
||||
|
||||
const maxCoins = getCurrentMaxCoins() * (isOptionOn("basic") ? 0.5 : 1);
|
||||
const maxCoins = getCurrentMaxCoins();
|
||||
const spawnableCoins =
|
||||
liveCount(gameState.coins) > getCurrentMaxCoins()
|
||||
? 1
|
||||
: Math.floor(maxCoins - liveCount(gameState.coins)) / 3;
|
||||
: Math.floor((maxCoins - liveCount(gameState.coins)) / 2);
|
||||
|
||||
const pointsPerCoin = Math.max(1, Math.ceil(coinsToSpawn / spawnableCoins));
|
||||
|
||||
|
@ -505,7 +491,6 @@ export function explodeBrick(
|
|||
gameState.perks.top_is_lava +
|
||||
gameState.perks.picky_eater +
|
||||
gameState.perks.asceticism * 3 +
|
||||
gameState.perks.zen +
|
||||
gameState.perks.passive_income +
|
||||
gameState.perks.addiction,
|
||||
ball.x,
|
||||
|
@ -550,10 +535,6 @@ export function explodeBrick(
|
|||
}
|
||||
}
|
||||
|
||||
if (isMovingWhilePassiveIncome(gameState)) {
|
||||
resetCombo(gameState, x, y);
|
||||
}
|
||||
|
||||
if (!isExplosion) {
|
||||
// color change
|
||||
if (
|
||||
|
@ -565,7 +546,7 @@ export function explodeBrick(
|
|||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
schedulGameSound(gameState, "colorChange", ball.x, 0.8);
|
||||
gameState.lastExplosion = gameState.levelTime;
|
||||
// gameState.lastExplosion = gameState.levelTime;
|
||||
gameState.ballsColor = color;
|
||||
if (!isOptionOn("basic")) {
|
||||
gameState.balls.forEach((ball) => {
|
||||
|
@ -637,7 +618,7 @@ export function schedulGameSound(
|
|||
) {
|
||||
if (!vol) return;
|
||||
if (!isOptionOn("sound")) return;
|
||||
if (gameState.computer_controlled) return;
|
||||
|
||||
x ??= gameState.offsetX + gameState.gameZoneWidth / 2;
|
||||
const ex = gameState.aboutToPlaySound[sound] as { vol: number; x: number };
|
||||
|
||||
|
@ -651,7 +632,9 @@ export function addToScore(gameState: GameState, coin: Coin) {
|
|||
addToTotalScore(gameState, coin.points);
|
||||
if (gameState.score > gameState.highScore && !gameState.creative) {
|
||||
gameState.highScore = gameState.score;
|
||||
localStorage.setItem("breakout-3-hs-short", gameState.score.toString());
|
||||
try {
|
||||
localStorage.setItem("breakout-3-hs-short", gameState.score.toString());
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!isOptionOn("basic")) {
|
||||
makeParticle(
|
||||
|
@ -660,9 +643,7 @@ export function addToScore(gameState: GameState, coin: Coin) {
|
|||
coin.previousY,
|
||||
(gameState.canvasWidth - coin.x) / 100,
|
||||
-coin.y / 100,
|
||||
gameState.perks.metamorphosis || isOptionOn("colorful_coins")
|
||||
? coin.color
|
||||
: "#ffd300",
|
||||
getCoinRenderColor(gameState, coin),
|
||||
|
||||
true,
|
||||
gameState.coinSize / 2,
|
||||
|
@ -703,6 +684,7 @@ export async function setLevel(gameState: GameState, l: number) {
|
|||
gameState.winAt = 0;
|
||||
gameState.levelWallBounces = 0;
|
||||
gameState.lastPuckMove = 0;
|
||||
gameState.lastZenComboIncrease = 0;
|
||||
gameState.autoCleanUses = 0;
|
||||
gameState.lastTickDown = gameState.levelTime;
|
||||
gameState.levelStartScore = gameState.score;
|
||||
|
@ -903,34 +885,34 @@ export function coinBrickHitCheck(gameState: GameState, coin: Coin) {
|
|||
hitsSomething(x, y, radius)) ||
|
||||
undefined;
|
||||
|
||||
if (gameState.perks.ghost_coins) {
|
||||
// slow down
|
||||
if (typeof (vhit ?? hhit ?? chit) !== "undefined") {
|
||||
if (typeof (vhit ?? hhit ?? chit) !== "undefined") {
|
||||
if (gameState.perks.ghost_coins) {
|
||||
// slow down
|
||||
coin.vy *= 1 - 0.2 / gameState.perks.ghost_coins;
|
||||
coin.vx *= 1 - 0.2 / gameState.perks.ghost_coins;
|
||||
}
|
||||
} else {
|
||||
if (typeof vhit !== "undefined" || typeof chit !== "undefined") {
|
||||
coin.y = coin.previousY;
|
||||
coin.vy *= -1;
|
||||
} else {
|
||||
if (typeof vhit !== "undefined" || typeof chit !== "undefined") {
|
||||
coin.y = coin.previousY;
|
||||
coin.vy *= -1;
|
||||
|
||||
// Roll on corners
|
||||
const leftHit = gameState.bricks[brickIndex(x - radius, y + radius)];
|
||||
const rightHit = gameState.bricks[brickIndex(x + radius, y + radius)];
|
||||
// Roll on corners
|
||||
const leftHit = gameState.bricks[brickIndex(x - radius, y + radius)];
|
||||
const rightHit = gameState.bricks[brickIndex(x + radius, y + radius)];
|
||||
|
||||
if (leftHit && !rightHit) {
|
||||
coin.vx += 1;
|
||||
coin.sa -= 1;
|
||||
if (leftHit && !rightHit) {
|
||||
coin.vx += 1;
|
||||
coin.sa -= 1;
|
||||
}
|
||||
if (!leftHit && rightHit) {
|
||||
coin.vx -= 1;
|
||||
coin.sa += 1;
|
||||
}
|
||||
}
|
||||
if (!leftHit && rightHit) {
|
||||
coin.vx -= 1;
|
||||
coin.sa += 1;
|
||||
if (typeof hhit !== "undefined" || typeof chit !== "undefined") {
|
||||
coin.x = coin.previousX;
|
||||
coin.vx *= -1;
|
||||
}
|
||||
}
|
||||
if (typeof hhit !== "undefined" || typeof chit !== "undefined") {
|
||||
coin.x = coin.previousX;
|
||||
coin.vx *= -1;
|
||||
}
|
||||
}
|
||||
return vhit ?? hhit ?? chit;
|
||||
}
|
||||
|
@ -959,7 +941,10 @@ export function bordersHitCheck(
|
|||
let vhit = 0,
|
||||
hhit = 0;
|
||||
|
||||
if (coin.x < gameState.offsetXRoundedDown + radius) {
|
||||
if (
|
||||
coin.x < gameState.offsetXRoundedDown + radius &&
|
||||
gameState.perks.left_is_lava < 2
|
||||
) {
|
||||
coin.x =
|
||||
gameState.offsetXRoundedDown +
|
||||
radius +
|
||||
|
@ -967,12 +952,15 @@ export function bordersHitCheck(
|
|||
coin.vx *= -1;
|
||||
hhit = 1;
|
||||
}
|
||||
if (coin.y < radius) {
|
||||
if (coin.y < radius && gameState.perks.top_is_lava < 2) {
|
||||
coin.y = radius + (radius - coin.y);
|
||||
coin.vy *= -1;
|
||||
vhit = 1;
|
||||
}
|
||||
if (coin.x > gameState.canvasWidth - gameState.offsetXRoundedDown - radius) {
|
||||
if (
|
||||
coin.x > gameState.canvasWidth - gameState.offsetXRoundedDown - radius &&
|
||||
gameState.perks.right_is_lava < 2
|
||||
) {
|
||||
coin.x =
|
||||
gameState.canvasWidth -
|
||||
gameState.offsetXRoundedDown -
|
||||
|
@ -992,14 +980,14 @@ export function gameStateTick(
|
|||
frames = 1,
|
||||
) {
|
||||
// Ai movement of puck
|
||||
if (gameState.computer_controlled) computerControl(gameState);
|
||||
if (gameState.startParams.computer_controlled) computerControl(gameState);
|
||||
|
||||
gameState.runStatistics.max_combo = Math.max(
|
||||
gameState.runStatistics.max_combo,
|
||||
gameState.combo,
|
||||
);
|
||||
|
||||
gameState.lastCombo = gameState.combo;
|
||||
zenTick(gameState);
|
||||
|
||||
if (
|
||||
gameState.perks.addiction &&
|
||||
|
@ -1015,7 +1003,6 @@ export function gameStateTick(
|
|||
}
|
||||
|
||||
gameState.balls = gameState.balls.filter((ball) => !ball.destroyed);
|
||||
|
||||
const remainingBricks = gameState.bricks.filter(
|
||||
(b) => b && b !== "black",
|
||||
).length;
|
||||
|
@ -1025,17 +1012,19 @@ export function gameStateTick(
|
|||
gameState.lastBrickBroken = 0;
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.levelTime > gameState.lastTickDown + 1000 &&
|
||||
gameState.perks.hot_start
|
||||
) {
|
||||
gameState.lastTickDown = gameState.levelTime;
|
||||
decreaseCombo(
|
||||
gameState,
|
||||
gameState.perks.hot_start,
|
||||
gameState.puckPosition,
|
||||
gameState.gameZoneHeight - 2 * gameState.puckHeight,
|
||||
);
|
||||
if (gameState.perks.hot_start) {
|
||||
if (gameState.combo === baseCombo(gameState)) {
|
||||
// Give 1s of time between catching a coin and tick down
|
||||
gameState.lastTickDown = gameState.levelTime;
|
||||
} else if (gameState.levelTime > gameState.lastTickDown + 1000) {
|
||||
gameState.lastTickDown = gameState.levelTime;
|
||||
decreaseCombo(
|
||||
gameState,
|
||||
gameState.perks.hot_start,
|
||||
gameState.puckPosition,
|
||||
gameState.gameZoneHeight - 2 * gameState.puckHeight,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -1068,8 +1057,8 @@ export function gameStateTick(
|
|||
// instant win condition
|
||||
(gameState.levelTime && !remainingBricks && !liveCount(gameState.coins))
|
||||
) {
|
||||
if (gameState.computer_controlled) {
|
||||
startComputerControlledGame();
|
||||
if (gameState.startParams.computer_controlled) {
|
||||
startComputerControlledGame(gameState.startParams.stress);
|
||||
} else if (gameState.currentLevel + 1 < max_levels(gameState)) {
|
||||
setLevel(gameState, gameState.currentLevel + 1);
|
||||
} else {
|
||||
|
@ -1160,12 +1149,24 @@ export function gameStateTick(
|
|||
|
||||
const ratio =
|
||||
1 -
|
||||
((gameState.perks.viscosity * 0.03 + 0.002) * frames) /
|
||||
((gameState.perks.viscosity * 0.03 +
|
||||
0.002 +
|
||||
(coin.y > gameState.gameZoneHeight ? 0.2 : 0)) *
|
||||
frames) /
|
||||
(1 + gameState.perks.etherealcoins);
|
||||
|
||||
if (!gameState.perks.etherealcoins) {
|
||||
coin.vy *= ratio;
|
||||
coin.vx *= ratio;
|
||||
}
|
||||
if (
|
||||
coin.y > gameState.gameZoneHeight &&
|
||||
coin.floatingTime < gameState.perks.buoy * 30
|
||||
) {
|
||||
coin.floatingTime += frames;
|
||||
coin.vy -= 1.5;
|
||||
}
|
||||
|
||||
if (coin.vx > 7 * gameState.baseSpeed) coin.vx = 7 * gameState.baseSpeed;
|
||||
if (coin.vx < -7 * gameState.baseSpeed)
|
||||
coin.vx = -7 * gameState.baseSpeed;
|
||||
|
@ -1203,9 +1204,7 @@ export function gameStateTick(
|
|||
coin.y,
|
||||
0,
|
||||
dvy * 10,
|
||||
gameState.perks.metamorphosis || isOptionOn("colorful_coins")
|
||||
? coin.color
|
||||
: "#ffd300",
|
||||
getCoinRenderColor(gameState, coin),
|
||||
true,
|
||||
5,
|
||||
250,
|
||||
|
@ -1213,8 +1212,84 @@ export function gameStateTick(
|
|||
}
|
||||
|
||||
const speed = (Math.abs(coin.vx) + Math.abs(coin.vy)) * 10;
|
||||
|
||||
const hitBorder = bordersHitCheck(gameState, coin, coin.size / 2, frames);
|
||||
|
||||
if (
|
||||
gameState.perks.wrap_left > 1 &&
|
||||
hitBorder % 2 &&
|
||||
coin.previousX < gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
) {
|
||||
schedulGameSound(gameState, "plouf", coin.x, 1);
|
||||
coin.x =
|
||||
gameState.offsetX + gameState.gameZoneWidth - gameState.coinSize;
|
||||
if (coin.vx > 0) {
|
||||
coin.vx *= -1;
|
||||
}
|
||||
if (!isOptionOn("basic")) {
|
||||
spawnExplosion(gameState, 3, coin.x, coin.y, "#6262EA");
|
||||
spawnImplosion(
|
||||
gameState,
|
||||
3,
|
||||
coin.previousX,
|
||||
coin.previousY,
|
||||
"#6262EA",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.perks.wrap_right > 1 &&
|
||||
hitBorder % 2 &&
|
||||
coin.previousX > gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
) {
|
||||
schedulGameSound(gameState, "plouf", coin.x, 1);
|
||||
coin.x = gameState.offsetX + gameState.coinSize;
|
||||
|
||||
if (coin.vx < 0) {
|
||||
coin.vx *= -1;
|
||||
}
|
||||
if (!isOptionOn("basic")) {
|
||||
spawnExplosion(gameState, 3, coin.x, coin.y, "#6262EA");
|
||||
spawnImplosion(
|
||||
gameState,
|
||||
3,
|
||||
coin.previousX,
|
||||
coin.previousY,
|
||||
"#6262EA",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
coin.previousY < gameState.gameZoneHeight &&
|
||||
coin.y > gameState.gameZoneHeight &&
|
||||
coin.vy > 0 &&
|
||||
speed > 20 &&
|
||||
!coin.floatingTime
|
||||
) {
|
||||
schedulGameSound(
|
||||
gameState,
|
||||
"plouf",
|
||||
coin.x,
|
||||
(clamp(speed, 20, 100) / 100) * 0.2,
|
||||
);
|
||||
if (gameState.perks.compound_interest) {
|
||||
resetCombo(gameState, coin.x, coin.y);
|
||||
}
|
||||
if (!isOptionOn("basic")) {
|
||||
makeParticle(
|
||||
gameState,
|
||||
coin.x,
|
||||
gameState.gameZoneHeight,
|
||||
-coin.vx / 5,
|
||||
-coin.vy / 5,
|
||||
getCoinRenderColor(gameState, coin),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
coin.y > gameState.gameZoneHeight - coinRadius - gameState.puckHeight &&
|
||||
coin.y < gameState.gameZoneHeight + gameState.puckHeight + coin.vy &&
|
||||
|
@ -1222,24 +1297,31 @@ export function gameStateTick(
|
|||
coinRadius +
|
||||
gameState.puckWidth / 2 +
|
||||
// a bit of margin to be nice , negative in case it's a negative coin
|
||||
gameState.puckHeight * (coin.points ? 1 : -1)
|
||||
gameState.puckHeight * (coin.points ? 1 : -1) &&
|
||||
!isMovingWhilePassiveIncome(gameState)
|
||||
) {
|
||||
addToScore(gameState, coin);
|
||||
destroy(gameState.coins, coinIndex);
|
||||
} else if (coin.y > gameState.canvasHeight + coinRadius * 10) {
|
||||
} else if (
|
||||
coin.y > gameState.canvasHeight + coinRadius * 10 ||
|
||||
coin.y < -coinRadius * 10 ||
|
||||
coin.x < -coinRadius * 10 ||
|
||||
coin.x > gameState.canvasWidth + coinRadius * 10
|
||||
) {
|
||||
gameState.levelLostCoins += coin.points;
|
||||
destroy(gameState.coins, coinIndex);
|
||||
if (gameState.perks.compound_interest) {
|
||||
resetCombo(gameState, coin.x, gameState.gameZoneHeight - 20);
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.combo < gameState.perks.fountain_toss * 30 &&
|
||||
Math.random() < (1 / gameState.combo) * gameState.perks.fountain_toss
|
||||
Math.random() / coin.points <
|
||||
(1 / gameState.combo) * gameState.perks.fountain_toss
|
||||
) {
|
||||
increaseCombo(gameState, 1, coin.x, gameState.gameZoneHeight - 20);
|
||||
increaseCombo(gameState, 1, coin.x, coin.y);
|
||||
}
|
||||
}
|
||||
|
||||
const positionBeforeBrickBounceX = coin.x;
|
||||
const positionBeforeBrickBounceY = coin.y;
|
||||
const hitBrick = coinBrickHitCheck(gameState, coin);
|
||||
if (gameState.perks.metamorphosis && typeof hitBrick !== "undefined") {
|
||||
if (
|
||||
|
@ -1266,6 +1348,24 @@ export function gameStateTick(
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.perks.sticky_coins &&
|
||||
typeof hitBrick !== "undefined" &&
|
||||
(coin.color === gameState.bricks[hitBrick] ||
|
||||
gameState.perks.sticky_coins > 1)
|
||||
) {
|
||||
if (coin.collidedLastFrame) {
|
||||
coin.x = coin.previousX;
|
||||
coin.y = coin.previousY;
|
||||
} else {
|
||||
coin.x = positionBeforeBrickBounceX;
|
||||
coin.y = positionBeforeBrickBounceY;
|
||||
}
|
||||
coin.vx = 0;
|
||||
coin.vy = 0;
|
||||
}
|
||||
|
||||
// Sound and slow down
|
||||
if (
|
||||
(!gameState.perks.ghost_coins && typeof hitBrick !== "undefined") ||
|
||||
hitBorder
|
||||
|
@ -1280,10 +1380,9 @@ export function gameStateTick(
|
|||
if (speed > 20 && !coin.collidedLastFrame) {
|
||||
schedulGameSound(gameState, "coinBounce", coin.x, 0.2);
|
||||
}
|
||||
coin.collidedLastFrame = true;
|
||||
} else {
|
||||
coin.collidedLastFrame = false;
|
||||
}
|
||||
// remember collision
|
||||
coin.collidedLastFrame = !!(typeof hitBrick !== "undefined" || hitBorder);
|
||||
});
|
||||
|
||||
gameState.balls.forEach((ball) => ballTick(gameState, ball, frames));
|
||||
|
@ -1297,29 +1396,32 @@ export function gameStateTick(
|
|||
!b.destroyed &&
|
||||
distance2(a, b) < gameState.ballSize * gameState.ballSize
|
||||
) {
|
||||
// switch speeds
|
||||
let tempVx = a.vx;
|
||||
let tempVy = a.vy;
|
||||
a.vx = b.vx;
|
||||
a.vy = b.vy;
|
||||
b.vx = tempVx;
|
||||
b.vy = tempVy;
|
||||
|
||||
// Compute center
|
||||
let x = (a.x + b.x) / 2;
|
||||
let y = (a.y + b.y) / 2;
|
||||
const limit = gameState.baseSpeed;
|
||||
a.vx +=
|
||||
clamp(a.x - x, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
a.vy +=
|
||||
clamp(a.y - y, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
b.vx +=
|
||||
clamp(b.x - x, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
b.vy +=
|
||||
clamp(b.y - y, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
|
||||
// space out the balls with extra speed
|
||||
if (gameState.perks.shocks > 1) {
|
||||
const limit = (gameState.baseSpeed * gameState.perks.shocks) / 2;
|
||||
a.vx +=
|
||||
clamp(a.x - x, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
a.vy +=
|
||||
clamp(a.y - y, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
b.vx +=
|
||||
clamp(b.x - x, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
b.vy +=
|
||||
clamp(b.y - y, -limit, limit) +
|
||||
((Math.random() - 0.5) * limit) / 3;
|
||||
}
|
||||
let index = brickIndex(x, y);
|
||||
explosionAt(
|
||||
gameState,
|
||||
|
@ -1373,11 +1475,11 @@ export function gameStateTick(
|
|||
if (
|
||||
gameState.combo > baseCombo(gameState) &&
|
||||
!isOptionOn("basic") &&
|
||||
(gameState.combo - baseCombo(gameState)) * Math.random() > 5
|
||||
(gameState.combo - baseCombo(gameState)) * Math.random() * frames > 5
|
||||
) {
|
||||
// The red should still be visible on a white bg
|
||||
|
||||
if (gameState.perks.top_is_lava) {
|
||||
if (gameState.perks.top_is_lava == 1) {
|
||||
makeParticle(
|
||||
gameState,
|
||||
gameState.offsetXRoundedDown +
|
||||
|
@ -1392,7 +1494,7 @@ export function gameStateTick(
|
|||
);
|
||||
}
|
||||
|
||||
if (gameState.perks.left_is_lava) {
|
||||
if (gameState.perks.left_is_lava == 1) {
|
||||
makeParticle(
|
||||
gameState,
|
||||
gameState.offsetXRoundedDown,
|
||||
|
@ -1406,7 +1508,7 @@ export function gameStateTick(
|
|||
);
|
||||
}
|
||||
|
||||
if (gameState.perks.right_is_lava) {
|
||||
if (gameState.perks.right_is_lava == 1) {
|
||||
makeParticle(
|
||||
gameState,
|
||||
gameState.offsetXRoundedDown + gameState.gameZoneWidthRoundedUp,
|
||||
|
@ -1445,7 +1547,10 @@ export function gameStateTick(
|
|||
100 * (Math.random() + 1),
|
||||
);
|
||||
}
|
||||
if (gameState.perks.streak_shots) {
|
||||
if (
|
||||
gameState.perks.streak_shots &&
|
||||
!isMovingWhilePassiveIncome(gameState)
|
||||
) {
|
||||
const pos = 0.5 - Math.random();
|
||||
makeParticle(
|
||||
gameState,
|
||||
|
@ -1461,6 +1566,41 @@ export function gameStateTick(
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.perks.wrap_left &&
|
||||
gameState.perks.left_is_lava < 2 &&
|
||||
Math.random() * frames > 0.1
|
||||
) {
|
||||
makeParticle(
|
||||
gameState,
|
||||
gameState.offsetXRoundedDown,
|
||||
Math.random() * gameState.gameZoneHeight,
|
||||
5,
|
||||
(Math.random() - 0.5) * 10,
|
||||
"#6262EA",
|
||||
true,
|
||||
gameState.coinSize / 2,
|
||||
100 * (Math.random() + 1),
|
||||
);
|
||||
}
|
||||
if (
|
||||
gameState.perks.wrap_right &&
|
||||
gameState.perks.right_is_lava < 2 &&
|
||||
Math.random() * frames > 0.1
|
||||
) {
|
||||
makeParticle(
|
||||
gameState,
|
||||
gameState.offsetXRoundedDown + gameState.gameZoneWidth,
|
||||
Math.random() * gameState.gameZoneHeight,
|
||||
-5,
|
||||
(Math.random() - 0.5) * 10,
|
||||
"#6262EA",
|
||||
true,
|
||||
gameState.coinSize / 2,
|
||||
100 * (Math.random() + 1),
|
||||
);
|
||||
}
|
||||
|
||||
// Respawn what's needed, show particles
|
||||
forEachLiveOne(gameState.respawns, (r, ri) => {
|
||||
if (gameState.bricks[r.index]) {
|
||||
|
@ -1575,6 +1715,7 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
}
|
||||
if (
|
||||
gameState.perks.puck_repulse_ball &&
|
||||
!isMovingWhilePassiveIncome(gameState) &&
|
||||
Math.abs(ball.x - gameState.puckPosition) <
|
||||
gameState.puckWidth / 2 +
|
||||
(gameState.ballSize * (9 + gameState.perks.puck_repulse_ball)) / 10
|
||||
|
@ -1598,10 +1739,51 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
frames,
|
||||
);
|
||||
if (borderHitCode) {
|
||||
ball.sidesHitsSinceBounce++;
|
||||
if (ball.sidesHitsSinceBounce <= gameState.perks.three_cushion * 3) {
|
||||
increaseCombo(gameState, 1, ball.x, ball.y);
|
||||
}
|
||||
if (
|
||||
gameState.perks.wrap_left &&
|
||||
borderHitCode % 2 &&
|
||||
// x might be moved by wrap so we rely on previousX
|
||||
ball.previousX < gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
) {
|
||||
schedulGameSound(gameState, "plouf", ball.x, 1);
|
||||
ball.x = gameState.offsetX + gameState.gameZoneWidth - gameState.ballSize;
|
||||
if (ball.vx > 0) {
|
||||
ball.vx *= -1;
|
||||
}
|
||||
|
||||
if (!isOptionOn("basic")) {
|
||||
spawnExplosion(gameState, 7, ball.x, ball.y, "#6262EA");
|
||||
spawnImplosion(gameState, 7, ball.previousX, ball.previousY, "#6262EA");
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.perks.wrap_right &&
|
||||
borderHitCode % 2 &&
|
||||
// x might be moved by wrap so we rely on previousX
|
||||
ball.previousX > gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
) {
|
||||
schedulGameSound(gameState, "plouf", ball.x, 1);
|
||||
ball.x = gameState.offsetX + gameState.ballSize;
|
||||
|
||||
if (ball.vx < 0) {
|
||||
ball.vx *= -1;
|
||||
}
|
||||
if (!isOptionOn("basic")) {
|
||||
spawnExplosion(gameState, 7, ball.x, ball.y, "#6262EA");
|
||||
spawnImplosion(gameState, 7, ball.previousX, ball.previousY, "#6262EA");
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.perks.left_is_lava &&
|
||||
borderHitCode % 2 &&
|
||||
ball.x < gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
// x might be moved by wrap so we rely on previousX
|
||||
ball.previousX < gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
) {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
|
@ -1609,21 +1791,17 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
if (
|
||||
gameState.perks.right_is_lava &&
|
||||
borderHitCode % 2 &&
|
||||
ball.x > gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
// x might be moved by wrap so we rely on previousX
|
||||
ball.previousX > gameState.offsetX + gameState.gameZoneWidth / 2
|
||||
) {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
|
||||
if (gameState.perks.top_is_lava && borderHitCode >= 2) {
|
||||
resetCombo(gameState, ball.x, ball.y + gameState.ballSize * 3);
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
if (gameState.perks.trampoline) {
|
||||
decreaseCombo(
|
||||
gameState,
|
||||
gameState.perks.trampoline,
|
||||
ball.x,
|
||||
ball.y + gameState.ballSize,
|
||||
);
|
||||
decreaseCombo(gameState, gameState.perks.trampoline, ball.x, ball.y);
|
||||
}
|
||||
|
||||
schedulGameSound(gameState, "wallBeep", ball.x, 1);
|
||||
|
@ -1636,7 +1814,8 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
gameState.gameZoneHeight - gameState.puckHeight - gameState.ballSize / 2;
|
||||
const ballIsUnderPuck =
|
||||
Math.abs(ball.x - gameState.puckPosition) <
|
||||
gameState.ballSize / 2 + gameState.puckWidth / 2;
|
||||
gameState.ballSize / 2 + gameState.puckWidth / 2 &&
|
||||
!isMovingWhilePassiveIncome(gameState);
|
||||
if (
|
||||
ball.y > ylimit &&
|
||||
ball.vy > 0 &&
|
||||
|
@ -1664,9 +1843,15 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
if (gameState.perks.streak_shots) {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
if (gameState.perks.trampoline) {
|
||||
increaseCombo(gameState, gameState.perks.trampoline, ball.x, ball.y);
|
||||
}
|
||||
|
||||
increaseCombo(
|
||||
gameState,
|
||||
gameState.perks.trampoline +
|
||||
gameState.perks.happy_family * Math.max(0, gameState.balls.length - 1),
|
||||
ball.x,
|
||||
ball.y,
|
||||
);
|
||||
|
||||
if (
|
||||
gameState.perks.nbricks &&
|
||||
ball.hitSinceBounce < gameState.perks.nbricks
|
||||
|
@ -1681,7 +1866,7 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
(gameState.levelMisses / 10 / gameState.perks.forgiving) *
|
||||
(gameState.combo - baseCombo(gameState)),
|
||||
);
|
||||
decreaseCombo(gameState, loss, ball.x, ball.y - gameState.ballSize);
|
||||
decreaseCombo(gameState, loss, ball.x, ball.y);
|
||||
} else {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
|
@ -1699,19 +1884,26 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
gameState.runStatistics.puck_bounces++;
|
||||
ball.hitSinceBounce = 0;
|
||||
ball.brokenSinceBounce = 0;
|
||||
ball.sidesHitsSinceBounce = 0;
|
||||
ball.sapperUses = 0;
|
||||
ball.piercePoints = gameState.perks.pierce * 3;
|
||||
}
|
||||
|
||||
if (
|
||||
gameState.running &&
|
||||
ball.y > gameState.gameZoneHeight + gameState.ballSize / 2
|
||||
(ball.y > gameState.gameZoneHeight + gameState.ballSize / 2 ||
|
||||
ball.y < -gameState.gameZoneHeight ||
|
||||
ball.x < -gameState.gameZoneHeight ||
|
||||
ball.x > gameState.canvasWidth + gameState.gameZoneHeight)
|
||||
) {
|
||||
ball.destroyed = true;
|
||||
gameState.runStatistics.balls_lost++;
|
||||
if (gameState.perks.happy_family) {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
if (!gameState.balls.find((b) => !b.destroyed)) {
|
||||
if (gameState.computer_controlled) {
|
||||
startComputerControlledGame();
|
||||
if (gameState.startParams.computer_controlled) {
|
||||
startComputerControlledGame(gameState.startParams.stress);
|
||||
} else {
|
||||
gameOver(
|
||||
t("gameOver.lost.title"),
|
||||
|
@ -1738,6 +1930,9 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
const initialBrickColor = gameState.bricks[hitBrick];
|
||||
ball.hitSinceBounce++;
|
||||
|
||||
if (!ball.sidesHitsSinceBounce && gameState.perks.three_cushion) {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
}
|
||||
if (gameState.perks.nbricks) {
|
||||
if (ball.hitSinceBounce > gameState.perks.nbricks) {
|
||||
resetCombo(gameState, ball.x, ball.y);
|
||||
|
@ -1782,7 +1977,7 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
|
|||
|
||||
if (!gameState.brickHP[hitBrick]) {
|
||||
ball.brokenSinceBounce++;
|
||||
|
||||
applyOttawaTreatyPerk(gameState, hitBrick, ball);
|
||||
explodeBrick(gameState, hitBrick, ball, false);
|
||||
if (
|
||||
ball.sapperUses < gameState.perks.sapper &&
|
||||
|
@ -1910,6 +2105,7 @@ function makeCoin(
|
|||
p.points = points;
|
||||
p.weight = weight;
|
||||
p.metamorphosisPoints = gameState.perks.metamorphosis;
|
||||
p.floatingTime = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1948,8 +2144,12 @@ function makeText(
|
|||
) {
|
||||
append(gameState.texts, (p: Partial<TextFlash>) => {
|
||||
p.time = gameState.levelTime;
|
||||
p.x = x;
|
||||
p.y = y;
|
||||
p.x = clamp(x, 20, gameState.canvasWidth - 20);
|
||||
p.y = clamp(
|
||||
y,
|
||||
40,
|
||||
gameState.gameZoneHeight - gameState.puckHeight - gameState.ballSize,
|
||||
);
|
||||
p.color = color;
|
||||
p.size = size;
|
||||
p.duration = clamp(duration, 400, 2000);
|
||||
|
@ -2083,3 +2283,51 @@ function goToNearestBrick(
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
function applyOttawaTreatyPerk(
|
||||
gameState: GameState,
|
||||
index: number,
|
||||
ball: Ball,
|
||||
) {
|
||||
if (!gameState.perks.ottawa_treaty) return;
|
||||
if (ball.sapperUses) return;
|
||||
|
||||
const originalColor = gameState.bricks[index];
|
||||
if (originalColor == "black") return;
|
||||
const x = index % gameState.gridSize;
|
||||
const y = Math.floor(index / gameState.gridSize);
|
||||
let converted = 0;
|
||||
for (let dx = -1; dx <= 1; dx++)
|
||||
for (let dy = -1; dy <= 1; dy++)
|
||||
if (dx || dy) {
|
||||
const nIndex = getRowColIndex(gameState, y + dy, x + dx);
|
||||
if (gameState.bricks[nIndex] && gameState.bricks[nIndex] === "black") {
|
||||
setBrick(gameState, nIndex, originalColor);
|
||||
schedulGameSound(
|
||||
gameState,
|
||||
"colorChange",
|
||||
brickCenterX(gameState, index),
|
||||
1,
|
||||
);
|
||||
// Avoid infinite bricks generation hack
|
||||
ball.sapperUses = Infinity;
|
||||
converted++;
|
||||
// Don't convert more than one brick per hit normally
|
||||
if (converted >= gameState.perks.ottawa_treaty) return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
export function zenTick(gameState: GameState) {
|
||||
if (!gameState.perks.zen) return;
|
||||
if (gameState.levelTime > gameState.lastZenComboIncrease + 3000) {
|
||||
gameState.lastZenComboIncrease = gameState.levelTime;
|
||||
increaseCombo(
|
||||
gameState,
|
||||
gameState.perks.zen,
|
||||
gameState.puckPosition,
|
||||
gameState.gameZoneHeight - gameState.puckHeight,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
Ball,
|
||||
Coin,
|
||||
GameState,
|
||||
Level,
|
||||
PerkId,
|
||||
|
@ -12,7 +13,8 @@ import { t } from "./i18n/i18n";
|
|||
import { clamp } from "./pure_functions";
|
||||
import { rawUpgrades } from "./upgrades";
|
||||
import { hashCode } from "./getLevelBackground";
|
||||
import { getTotalScore } from "./settings";
|
||||
import { getSettingValue, getTotalScore } from "./settings";
|
||||
import { isOptionOn } from "./options";
|
||||
|
||||
export function describeLevel(level: Level) {
|
||||
let bricks = 0,
|
||||
|
@ -240,6 +242,7 @@ export function defaultSounds() {
|
|||
explode: { vol: 0, x: 0 },
|
||||
lifeLost: { vol: 0, x: 0 },
|
||||
coinCatch: { vol: 0, x: 0 },
|
||||
plouf: { vol: 0, x: 0 },
|
||||
colorChange: { vol: 0, x: 0 },
|
||||
},
|
||||
};
|
||||
|
@ -316,7 +319,6 @@ function isExcluded(id: PerkId) {
|
|||
}
|
||||
|
||||
export function getLevelUnlockCondition(levelIndex: number) {
|
||||
// Returns "" if level is unlocked, otherwise a string explaining how to unlock it
|
||||
let required: UpgradeLike[] = [],
|
||||
forbidden: UpgradeLike[] = [],
|
||||
minScore = Math.max(-1000 + 100 * levelIndex, 0);
|
||||
|
@ -390,12 +392,34 @@ export function reasonLevelIsLocked(
|
|||
}
|
||||
}
|
||||
|
||||
export function ballTransparency(ball: Ball, gameState: GameState) {
|
||||
if (!gameState.perks.transparency) return 0;
|
||||
return clamp(
|
||||
gameState.perks.transparency *
|
||||
(1 - (ball.y / gameState.gameZoneHeight) * 1.2),
|
||||
0,
|
||||
1,
|
||||
export function getCoinRenderColor(gameState: GameState, coin: Coin) {
|
||||
if (
|
||||
gameState.perks.metamorphosis ||
|
||||
isOptionOn("colorful_coins") ||
|
||||
gameState.perks.hypnosis ||
|
||||
gameState.perks.sticky_coins ||
|
||||
gameState.perks.rainbow
|
||||
)
|
||||
return coin.color;
|
||||
return "#ffd300";
|
||||
}
|
||||
|
||||
export function getCornerOffset(gameState: GameState) {
|
||||
return (
|
||||
(gameState.levelTime
|
||||
? gameState.perks.corner_shot * gameState.brickWidth
|
||||
: 0) -
|
||||
gameState.perks.unbounded * gameState.brickWidth
|
||||
);
|
||||
}
|
||||
|
||||
export const isInWebView = !!window.location.href.includes("isInWebView=true");
|
||||
|
||||
export function hoursSpentPlaying() {
|
||||
try {
|
||||
const timePlayed = getSettingValue("breakout_71_total_play_time", 0);
|
||||
return Math.floor(timePlayed / 1000 / 60 / 60);
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@ export function generateSaveFileContent() {
|
|||
const key = localStorage.key(i) as string;
|
||||
// Avoid including recovery info in the recovery info
|
||||
if (["recovery_data"].includes(key)) continue;
|
||||
const value = localStorage.getItem(key) as string;
|
||||
localStorageContent[key] = value;
|
||||
try {
|
||||
const value = localStorage.getItem(key) as string;
|
||||
localStorageContent[key] = JSON.parse(value);
|
||||
} catch (e) {}
|
||||
}
|
||||
return JSON.stringify(localStorageContent);
|
||||
return localStorageContent;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,29 @@
|
|||
"confirmRestart.text": "أنت على وشك بدء لعبة جديدة. هل أنت متأكد من رغبتك في المتابعة؟",
|
||||
"confirmRestart.title": "بدء لعبة جديدة؟",
|
||||
"confirmRestart.yes": "إعادة تشغيل اللعبة",
|
||||
"editor.editing.bigger": "زيادة حجم المستوى",
|
||||
"editor.editing.color": "اختر لونًا من قائمة الألوان (بحد أقصى 5 لكل مستوى)",
|
||||
"editor.editing.copy": "نسخ رمز المستوى",
|
||||
"editor.editing.copy_help": "ألصقه في قناة #levels في Discord الخاص بنا",
|
||||
"editor.editing.credit": "الاعتمادات والمصدر",
|
||||
"editor.editing.credit_prompt": "أدخل عنوان URL المصدر أو شرحًا لمستواك.",
|
||||
"editor.editing.delete": "حذف المستوى",
|
||||
"editor.editing.down": "انزل كل الطوب إلى الأسفل",
|
||||
"editor.editing.help": "ثم انقر على البلاط لتلوينه.",
|
||||
"editor.editing.left": "نقل جميع الطوب إلى اليسار",
|
||||
"editor.editing.play": "العب هذا المستوى",
|
||||
"editor.editing.rename": "اسم المستوى",
|
||||
"editor.editing.rename_prompt": "الرجاء إدخال اسم جديد للمستوى",
|
||||
"editor.editing.right": "حرك كل الطوب إلى اليمين",
|
||||
"editor.editing.smaller": "تقليل حجم المستوى",
|
||||
"editor.editing.title": "مستوى التحرير: {{name}}",
|
||||
"editor.editing.up": "حرك كل الطوب لأعلى",
|
||||
"editor.help": "إنشاء مستويات مخصصة ومشاركتها لتضمينها في اللعبة.",
|
||||
"editor.import": "استيراد المستوى",
|
||||
"editor.import_instruction": "الصق رمز المستوى لاستيراده في قائمة المستويات الخاصة بك",
|
||||
"editor.locked": "احصل على مجموع نقاط قدره {{min}} لفتح القفل",
|
||||
"editor.new_level": "مستوى جديد",
|
||||
"editor.title": "محرر المستويات",
|
||||
"gameOver.creative": "لن يتم تسجيل هذا التشغيل.",
|
||||
"gameOver.cumulative_total": "لقد ارتفع مجموع درجاتك التراكمية من {{startTs}} إلى {{endTs}}.",
|
||||
"gameOver.lost.summary": "لقد أسقطت الكرة بعد التقاط {{score}} قطعة نقدية.",
|
||||
|
@ -32,12 +55,14 @@
|
|||
"history.columns.score": "نتيجة",
|
||||
"history.columns.started": "تاريخ",
|
||||
"history.help": "شاهد أفضل ألعابك {{count}} .",
|
||||
"history.include_past_versions": "",
|
||||
"history.locked": "العب عشر مباريات على الأقل لفتح القفل",
|
||||
"history.title": "سجل التشغيل",
|
||||
"lab.help": "جرب أي بناء تريده",
|
||||
"lab.instructions": "قم بتحديد الترقيات أدناه، ثم اختر المستوى للعب.",
|
||||
"lab.instructions": "حدد الترقيات والمستوى، ثم انقر فوق زر التشغيل أعلاه",
|
||||
"lab.menu_entry": "الوضع الإبداعي",
|
||||
"lab.reset": "إعادة تعيين الكل إلى 0",
|
||||
"lab.play": "يلعب",
|
||||
"lab.reset": "إعادة ضبط",
|
||||
"lab.select_level": "حدد المستوى للعب عليه",
|
||||
"lab.unlocks_at": "يتم فتحه عند إجمالي النتيجة {{score}}",
|
||||
"level_up.after_buttons": "لقد انتهيت للتو من المستوى {{level}}/{{max}}.",
|
||||
|
@ -139,6 +164,8 @@
|
|||
"score_panel.title": "{{score}} نقطة في المستوى {{level}}/{{max}} ",
|
||||
"score_panel.upcoming_levels": "المستويات القادمة :",
|
||||
"score_panel.upgrades_picked": "الترقيات التي تم اختيارها في هذه اللعبة:",
|
||||
"settings.autoplay": "التشغيل التلقائي",
|
||||
"settings.autoplay_help": "ابدأ جلسة مع ترقيات عشوائية ومجداف يتم التحكم فيه بواسطة الكمبيوتر",
|
||||
"settings.basic": "الرسومات الأساسية",
|
||||
"settings.basic_help": "أداء أفضل.",
|
||||
"settings.colorful_coins": "عملات معدنية ملونة",
|
||||
|
@ -163,12 +190,14 @@
|
|||
"settings.load_save_file_help": "حدد ملف الحفظ على جهازك",
|
||||
"settings.max_coins": " {{max}} عملات معدنية على الشاشة كحد أقصى",
|
||||
"settings.max_coins_help": "تجميلي فقط، لا يؤثر على النتيجة",
|
||||
"settings.max_particles": " {{max}} جسيمات كحد أقصى",
|
||||
"settings.max_particles_help": "يحدد عدد الجسيمات التي تظهر على الشاشة للتأثير البصري.",
|
||||
"settings.mobile": "الوضع المحمول",
|
||||
"settings.mobile_help": "يترك مساحة تحت المجداف.",
|
||||
"settings.pointer_lock": "قفل مؤشر الماوس",
|
||||
"settings.pointer_lock_help": "يقوم بقفل وإخفاء مؤشر الماوس.",
|
||||
"settings.precise_lighting": "إضاءة دقيقة",
|
||||
"settings.precise_lighting_help": "استخدم شبكة أصغر لتأثير الإضاءة الخلفية",
|
||||
"settings.probabilistic_lighting": "استمرار الرؤية",
|
||||
"settings.probabilistic_lighting_help": "تحسين الأداء عندما يكون هناك أكثر من 150 عملة عن طريق إعادة استخدام بعض الضوء من الإطار السابق",
|
||||
"settings.record": "تسجيل مقاطع فيديو للعبة",
|
||||
"settings.record_download": "تنزيل الفيديو ({{size}} ميجابايت)",
|
||||
"settings.record_help": "احصل على فيديو لكل مستوى.",
|
||||
|
@ -187,24 +216,30 @@
|
|||
"settings.show_fps_help": "مراقبة أداء التطبيق",
|
||||
"settings.show_stats": "عرض الإحصائيات في الوقت الحقيقي",
|
||||
"settings.show_stats_help": "العملات المعدنية، الوقت، الارتدادات، الأخطاء",
|
||||
"settings.smooth_lighting": "إضاءة سلسة",
|
||||
"settings.smooth_lighting_help": "طمس تأثيرات الإضاءة الخلفية لجعلها تبدو أقل مربعًا. يزيد هذا من التأخير.",
|
||||
"settings.sounds": "أصوات اللعبة",
|
||||
"settings.sounds_help": "قد يؤدي إلى إبطاء بعض الهواتف.",
|
||||
"settings.sounds_help": "أصوات صفير وبلبل و برررر",
|
||||
"settings.stress_test": "اختبار الإجهاد",
|
||||
"settings.stress_test_help": "ابدأ لعبة يتم التحكم فيها بواسطة روبوت باستخدام عدد كبير جدًا من العملات المعدنية، لاختبار حدود أداء جهازك.",
|
||||
"starting_perks.checked": "عند بدء لعبة جديدة، ستُمنح إحدى هذه المزايا. انقر على أي ميزة لاستبعادها.",
|
||||
"starting_perks.help": "اختر الترقيات الأولية الممكنة",
|
||||
"starting_perks.random": "لقد تم إزالة جميع المزايا، وسيكون الاختيار عشوائيًا.",
|
||||
"starting_perks.title": "امتيازات البداية",
|
||||
"starting_perks.unchecked": "لا يتم تقديم الامتيازات المذكورة أدناه كامتيازات ابتدائية، ولكن يمكنك النقر عليها لإضافتها إلى المجموعة.",
|
||||
"unlocks.greyed_out_help": "يمكن فتح الترقيات غير المفعّلة بزيادة مجموع نقاطك. يزداد مجموع النقاط مع كل نقطة تُسجّلها في اللعبة.",
|
||||
"unlocks.intro": "مجموع نقاطك هو {{ts}}. تجد أدناه جميع الترقيات والمستويات التي تقدمها اللعبة. انقر على ترقية أو مستوى أدناه لبدء لعبة تجريبية بها.",
|
||||
"unlocks.intro": "",
|
||||
"unlocks.just_unlocked": "تم فتح المستوى",
|
||||
"unlocks.just_unlocked_plural": "لقد قمت للتو بفتح {{count}} مستوى",
|
||||
"unlocks.level": "<h2>لقد قمت بفتح {{unlocked}} مستوى من أصل {{out_of}}</h2>\n<p>إليك جميع مستويات اللعبة، انقر على أحدها لتجربته.</p> ",
|
||||
"unlocks.level": "",
|
||||
"unlocks.level_description": "مستوى {{size}}×{{size}} مع {{bricks}} طوبة و {{colors}} لون و {{bombs}} قنبلة.",
|
||||
"unlocks.levels": "",
|
||||
"unlocks.minScore": "احصل على ${{minScore}} في جولة لفتح القفل.",
|
||||
"unlocks.minScoreWithPerks": "احصل على ${{minScore}} في جولة مع {{required}} ولكن بدون {{forbidden}} لفتح القفل.",
|
||||
"unlocks.minTotalScore": "تجميع إجمالي قدره{{score}}دولار",
|
||||
"unlocks.reached": "أفضل نتيجة حصلت عليها كانت {{reached}}.",
|
||||
"unlocks.title_upgrades": "لقد قمت بفتح {{unlocked}} ترقيات من أصل {{out_of}}",
|
||||
"unlocks.upgrades": "",
|
||||
"upgrades.addiction.name": "مدمن",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} مجموعة / لبنة، يتم إعادة تعيين المجموعة لمدة {{delay}}ثانية بعد كسر لبنة.",
|
||||
"upgrades.addiction.verbose_description": "يبدأ العد التنازلي بعد كسر أول لبنة من كل مستوى، ويتوقف عند تدمير جميع الطوب.",
|
||||
|
@ -237,6 +272,9 @@
|
|||
"upgrades.bricks_attract_coins.name": "الطوب يجذب العملات المعدنية",
|
||||
"upgrades.bricks_attract_coins.tooltip": "يساعدهم على البقاء هناك",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "عوامة",
|
||||
"upgrades.buoy.tooltip": "تطفو العملات المعدنية لمدة {{duration}} ثانية على الخط السفلي.",
|
||||
"upgrades.buoy.verbose_description": "يكون التأثير أكثر وضوحًا في الوضع المحمول",
|
||||
"upgrades.clairvoyant.name": "مستبصر",
|
||||
"upgrades.clairvoyant.tooltip": "شاهد المستويات القادمة، نقاط الصحة للطوب واتجاه الكرة",
|
||||
"upgrades.clairvoyant.verbose_description": "يساعدك على اختيار الترقيات المناسبة وفهم كيفية عمل الطوب المتين. يُضيف المستويان 2 و3 معلومات إضافية حول فائدة مشكوك فيها (متوفرة في وضع الحلقة).",
|
||||
|
@ -253,6 +291,9 @@
|
|||
"upgrades.corner_shot.name": "ضربة ركنية",
|
||||
"upgrades.corner_shot.tooltip": "يسمح للمجداف الخاص بك بالتداخل مع حدود الشاشة",
|
||||
"upgrades.corner_shot.verbose_description": "يُساعدك على التصويب في الزوايا. المستويات الأعلى تُتيح لك الوصول إلى مسافات أبعد.",
|
||||
"upgrades.double_or_nothing.name": "",
|
||||
"upgrades.double_or_nothing.tooltip": "",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "العملات المعدنية في الفضاء",
|
||||
"upgrades.etherealcoins.tooltip": "لم تعد العملات المعدنية تتأثر بالجاذبية",
|
||||
"upgrades.etherealcoins.verbose_description": "ستحافظ العملات المعدنية على سرعتها حتى بعد عدة ارتدادات، ولن تتأثر بالجاذبية بعد الآن.",
|
||||
|
@ -268,10 +309,13 @@
|
|||
"upgrades.forgiving.verbose_description": "أول خطأ في كل مستوى مجاني، ثم 10% من المجموعة، ثم 20% ..",
|
||||
"upgrades.fountain_toss.name": "رمي النافورة",
|
||||
"upgrades.fountain_toss.tooltip": "احصل على بعض المجموعات عندما تفوت بعض العملات المعدنية.",
|
||||
"upgrades.fountain_toss.verbose_description": "عندما تفوتك عملة معدنية وكان مجموعتك أقل من {{max}}، فإن مجموعتك لديها احتمالية {{lvl}}/مجموعة لتنمو بمقدار واحد.",
|
||||
"upgrades.fountain_toss.verbose_description": "عندما تفوتك عملة معدنية وكان مجموعتك أقل من المستوى*30، فإن مجموعتك لديها احتمالية نمو المستوى/المجموعة بمقدار واحد.",
|
||||
"upgrades.ghost_coins.name": "عملات الأشباح",
|
||||
"upgrades.ghost_coins.tooltip": "تمر العملات المعدنية ببطء عبر الطوب",
|
||||
"upgrades.ghost_coins.verbose_description": "إنها ليست مشكلة، بل ميزة! تتحرك العملات المعدنية ببطء عبر الطوب. المستويات الأعلى تسمح لها بالتحرك بشكل أسرع.",
|
||||
"upgrades.happy_family.name": "",
|
||||
"upgrades.happy_family.tooltip": "",
|
||||
"upgrades.happy_family.verbose_description": "",
|
||||
"upgrades.helium.name": "الهيليوم",
|
||||
"upgrades.helium.tooltip": "انعكست الجاذبية إلى اليسار واليمين من المجداف",
|
||||
"upgrades.helium.verbose_description": "يؤثر هذا على العملات المعدنية وسيسمح لها بالطفو حتى تصبح جاهزًا لالتقاطها.",
|
||||
|
@ -308,8 +352,11 @@
|
|||
"upgrades.one_more_choice.name": "خيار إضافي",
|
||||
"upgrades.one_more_choice.tooltip": "ستوفر عمليات رفع المستوى الإضافية {{lvl}} خيارًا إضافيًا في القائمة",
|
||||
"upgrades.one_more_choice.verbose_description": "ستحتوي كل قائمة ترقية على خيار إضافي. هذا لا يزيد من عدد الترقيات المتاحة.",
|
||||
"upgrades.ottawa_treaty.name": "معاهدة أوتاوا",
|
||||
"upgrades.ottawa_treaty.tooltip": "كسر الطوب بالقرب من القنبلة ينزع فتيلها",
|
||||
"upgrades.ottawa_treaty.verbose_description": "سيتم استبدال القنبلة القريبة بكتلة ملونة. إذا كان لديك سلاح نووي، فستفقد الكرة تأثيرها حتى الارتداد التالي. لا يمكن استبدال سوى قنبلة واحدة في كل مرة.",
|
||||
"upgrades.passive_income.name": "الدخل السلبي",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} مجموعة / لبنة، ما لم يتم تحريك المجداف في آخر {{time}}ثانية، ثم يتم إعادة تعيينه بدلاً من ذلك",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} مجموعة / لبنة، المجداف غير مهم {{time}}ثانية بعد التحرك",
|
||||
"upgrades.passive_income.verbose_description": "يمكن لبعض الامتيازات أن تساعد الكرات على القيام بما تريد دون الحاجة إلى القيام بأي شيء.",
|
||||
"upgrades.picky_eater.name": "آكل انتقائي",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} مجموعة لكل لبنة مكسورة، يتم إعادة تعيينها عند تغير لون الكرة",
|
||||
|
@ -363,13 +410,15 @@
|
|||
"upgrades.slow_down.name": "كرة أبطأ",
|
||||
"upgrades.slow_down.tooltip": "الكرة تتحرك بشكل أبطأ",
|
||||
"upgrades.slow_down.verbose_description": "تبدأ الكرة ببطء نسبيًا، لكنها ستتسارع قليلًا مع كل مستوى.\n\nكما ستتسارع إذا قضيت وقتًا طويلًا في مستوى واحد.\n\nهذه الميزة تجعلها أسهل في التحكم.\n\nيمكنك الحصول عليها في البداية دائمًا بتفعيل وضع الأطفال في القائمة.",
|
||||
"upgrades.smaller_puck.help_plural": "مجموعة مجداف أصغر وقاعدة أعلى",
|
||||
"upgrades.smaller_puck.name": "مجداف أصغر",
|
||||
"upgrades.smaller_puck.tooltip": "يمنح أيضًا +5 مجموعة أساسية",
|
||||
"upgrades.smaller_puck.verbose_description": "هذا يُصغّر حجم المجداف، مما يُسهّل نظريًا بعض الضربات الزاوية، ولكنه في الواقع يزيد من الصعوبة.\n\nلهذا السبب ستحصل أيضًا على مكافأة رائعة قدرها +٥ عملات لكل طوبة تُكسرها بعد التقاط هذا.",
|
||||
"upgrades.smaller_puck.tooltip": "يمنح أيضًا +{{percent}}% عملات معدنية",
|
||||
"upgrades.smaller_puck.verbose_description": "هذا يُصغّر حجم المضرب، مما يُسهّل نظريًا بعض الضربات الزاوية، ولكنه في الواقع يزيد من الصعوبة.\n\nلهذا السبب ستحصل أيضًا على مكافأة رائعة تتمثل في ظهور +٥٠٪ من العملات.",
|
||||
"upgrades.soft_reset.name": "إعادة الضبط الناعمة",
|
||||
"upgrades.soft_reset.tooltip": "إعادة تعيين المجموعة تحافظ على {{percent}}%",
|
||||
"upgrades.soft_reset.verbose_description": "الحد من تأثير إعادة تعيين المجموعة.",
|
||||
"upgrades.sticky_coins.name": "العملات المعدنية اللاصقة",
|
||||
"upgrades.sticky_coins.tooltip": "",
|
||||
"upgrades.sticky_coins.verbose_description": "",
|
||||
"upgrades.streak_shots.name": "سلسلة الضربات",
|
||||
"upgrades.streak_shots.tooltip": "مزيد من العملات المعدنية إذا قمت بكسر العديد من الطوب قبل القفز على المجداف.",
|
||||
"upgrades.streak_shots.verbose_description": "في كل مرة تكسر فيها لبنة، تزداد مجموعتك بمقدار واحد.\n\nولكن، بمجرد أن تلمس الكرة مضربك، تُعاد المجموعة إلى قيمتها الافتراضية.\n\nبمجرد أن تتجاوز مجموعتك القيمة الأساسية، سيُحاط مضربك بإطار أحمر لتذكيرك بأنه سيدمر مجموعتك إذا لمسته بالكرة.",
|
||||
|
@ -383,6 +432,9 @@
|
|||
"upgrades.telekinesis.name": "التحريك الذهني",
|
||||
"upgrades.telekinesis.tooltip": "يتحكم المضرب في مسار الكرة",
|
||||
"upgrades.telekinesis.verbose_description": "تتحكم بالكرة أثناء صعودها.",
|
||||
"upgrades.three_cushion.name": "ثلاث وسائد",
|
||||
"upgrades.three_cushion.tooltip": "",
|
||||
"upgrades.three_cushion.verbose_description": "كل ضربة على أحد الجانبين تزيد من قوة الضربة بواحد، حتى +٣. بعد ذلك، لن تُكتسب أي ضربة حتى الارتداد التالي للمضرب.",
|
||||
"upgrades.top_is_lava.name": "السماء هي الحد",
|
||||
"upgrades.top_is_lava.tooltip": "+{{lvl}} مجموعة لكل لبنة، يتم إعادة ضبطها عند الوصول إلى الجزء العلوي",
|
||||
"upgrades.top_is_lava.verbose_description": "كلما كسرتَ لبنة، ستزداد مجموعتك بمقدار واحد. مع ذلك، ستُعاد ضبط مجموعتك بمجرد وصول الكرة إلى أعلى الشاشة.\n\nعندما تتجاوز مجموعتك الحد الأدنى، سيظهر شريط أحمر في الأعلى لتذكيرك بتجنب ضربها.",
|
||||
|
@ -390,7 +442,7 @@
|
|||
"upgrades.trampoline.tooltip": "+{{lvl}} مجموعة لكل ارتداد للمضرب، -{{lvl}} مجموعة لكل ارتداد على أي حدود",
|
||||
"upgrades.trampoline.verbose_description": "أحد ترقيات المجموعات النادرة التي لا تضيف شرط إعادة الضبط",
|
||||
"upgrades.transparency.name": "الشفافية",
|
||||
"upgrades.transparency.tooltip": "كلما كانت الكرة أعلى على الشاشة، زادت شفافيتها. وكلما زادت شفافيتها، زادت العملات التي تنتجها.",
|
||||
"upgrades.transparency.tooltip": "تصبح الكرة شفافة في الجزء العلوي من الشاشة. +{{percent}} % عملات معدنية عندما تكون جميع الكرات في حالة الشفافية الكاملة",
|
||||
"upgrades.transparency.verbose_description": "المستويات الأعلى تجعل الكرة شفافة بشكل أسرع وتزيد من مكافأة النقاط.",
|
||||
"upgrades.trickledown.name": "اقتصاد التسرب",
|
||||
"upgrades.trickledown.tooltip": "تظهر العملات المعدنية في الجزء العلوي من الشاشة.",
|
||||
|
@ -405,10 +457,16 @@
|
|||
"upgrades.wind.name": "رياح",
|
||||
"upgrades.wind.tooltip": "وضع المجداف يخلق الرياح",
|
||||
"upgrades.wind.verbose_description": "تعتمد الرياح على وضعية المضرب: يسارًا يهب يسارًا، ويمينًا يهب يمينًا. تؤثر على الكرات والعملات المعدنية.",
|
||||
"upgrades.wrap_left.name": "",
|
||||
"upgrades.wrap_left.tooltip": "",
|
||||
"upgrades.wrap_left.verbose_description": "",
|
||||
"upgrades.wrap_right.name": "",
|
||||
"upgrades.wrap_right.tooltip": "",
|
||||
"upgrades.wrap_right.verbose_description": "",
|
||||
"upgrades.yoyo.name": "يو يو",
|
||||
"upgrades.yoyo.tooltip": "الكرة تسقط نحو المضرب",
|
||||
"upgrades.yoyo.verbose_description": "إنه عكس التحريك الذهني، أي التحكم بالكرة أثناء سقوطها مرة أخرى إلى الأسفل.",
|
||||
"upgrades.zen.name": "زين",
|
||||
"upgrades.zen.tooltip": "+{{lvl}} مجموعة لكل لبنة، يتم إعادة ضبطها عند حدوث انفجار",
|
||||
"upgrades.zen.verbose_description": "في نهاية المطاف، هذه لعبة غير عنيفة."
|
||||
"upgrades.zen.tooltip": "",
|
||||
"upgrades.zen.verbose_description": ""
|
||||
}
|
||||
|
|
5558
src/i18n/b71.babel
5558
src/i18n/b71.babel
File diff suppressed because it is too large
Load diff
444
src/i18n/de.json
444
src/i18n/de.json
|
@ -1,149 +1,245 @@
|
|||
{
|
||||
"confirmRestart.no": "Abbrechen",
|
||||
"confirmRestart.text": "Sie sind dabei, ein neues Spiel zu beginnen. Sind Sie sicher, dass Sie weitermachen wollen?",
|
||||
"confirmRestart.title": "Ein neues Spiel beginnen?",
|
||||
"confirmRestart.yes": "Spiel neu starten",
|
||||
"gameOver.creative": "Dieser Lauf wird nicht aufgezeichnet.",
|
||||
"gameOver.cumulative_total": "Ihre kumulative Gesamtpunktzahl ist von {{startTs}} auf {{endTs}}gestiegen.",
|
||||
"gameOver.lost.summary": "Du hast den Ball fallen lassen, nachdem du {{score}} Münzen gefangen hast.",
|
||||
"confirmRestart.text": "Sie sind dabei, ein neues Spiel zu beginnen. Sind Sie sicher, dass Sie das wollen?",
|
||||
"confirmRestart.title": "Neues Spiel beginnen?",
|
||||
"confirmRestart.yes": "Spiel neustarten",
|
||||
"editor.editing.bigger": "Level vergrößern",
|
||||
"editor.editing.color": "Wähle eine Farbe aus der Farbliste (max. 5 pro Level)",
|
||||
"editor.editing.copy": "Levelcode kopieren",
|
||||
"editor.editing.copy_help": "Teile ihn im Kanal #levels auf unserem Discord",
|
||||
"editor.editing.credit": "Credits und Quellcode",
|
||||
"editor.editing.credit_prompt": "Gib die URL oder Erklärung deines Levels ein.",
|
||||
"editor.editing.delete": "Level löschen",
|
||||
"editor.editing.down": "Bewege alle Steine nach unten",
|
||||
"editor.editing.help": "Klicke dann auf eine Kachel, um sie einzufärben.",
|
||||
"editor.editing.left": "Bewege alle Steine nach links",
|
||||
"editor.editing.play": "Spiele dieses Level",
|
||||
"editor.editing.rename": "Levelname",
|
||||
"editor.editing.rename_prompt": "Gib einen neuen Namen für das Level ein",
|
||||
"editor.editing.right": "Bewege alle Steine nach rechts",
|
||||
"editor.editing.smaller": "Level verkleinern",
|
||||
"editor.editing.title": "Bearbeite Level: {{name}}",
|
||||
"editor.editing.up": "Bewege alle Steine nach oben",
|
||||
"editor.help": "Erstelle benutzerdefinierte Level und gib sie frei, um sie in das Spiel aufzunehmen.",
|
||||
"editor.import": "Importiere ein Level",
|
||||
"editor.import_instruction": "Füge einen Levelcode ein, um ihn in deine Levelliste zu importieren",
|
||||
"editor.locked": "Erreiche eine Gesamtpunktzahl von {{min}} zum freizuschalten",
|
||||
"editor.new_level": "Neues Level",
|
||||
"editor.title": "Level-Editor",
|
||||
"gameOver.creative": "Dieses Spiel wird nicht aufgezeichnet.",
|
||||
"gameOver.cumulative_total": "Ihre Gesamtpunktzahl ist von {{startTs}} auf {{endTs}}gestiegen.",
|
||||
"gameOver.lost.summary": "Du hast den Ball fallen lassen, nachdem du {{score}} Münzen gesammelt hast.",
|
||||
"gameOver.lost.title": "Spiel vorbei",
|
||||
"gameOver.stats.balls_lost": "Verlorene Bälle",
|
||||
"gameOver.stats.bricks_broken": "Ziegelsteine gebrochen",
|
||||
"gameOver.stats.bricks_per_minute": "Ziegelsteinbruch pro Minute",
|
||||
"gameOver.stats.bricks_broken": "Steine gebrochen",
|
||||
"gameOver.stats.bricks_per_minute": "Zerbrochene Steine pro Minute",
|
||||
"gameOver.stats.catch_rate": "Fangquote",
|
||||
"gameOver.stats.combo_avg": "Durchschnittliche Combo",
|
||||
"gameOver.stats.combo_max": "Max-Kombo",
|
||||
"gameOver.stats.duration_per_level": "Dauer pro Stufe",
|
||||
"gameOver.stats.combo_max": "Maximale Combo",
|
||||
"gameOver.stats.duration_per_level": "Dauer pro Level",
|
||||
"gameOver.stats.hit_rate": "Trefferquote",
|
||||
"gameOver.stats.intro": "Hier finden Sie Ihre Spielstatistik im Vergleich zu Ihren {{count}} besten Spielen.",
|
||||
"gameOver.stats.level_reached": "Erreichte Stufe",
|
||||
"gameOver.stats.intro": "",
|
||||
"gameOver.stats.level_reached": "Erreichtes Level",
|
||||
"gameOver.stats.total_score": "Gesamtpunktzahl",
|
||||
"gameOver.stats.upgrades_applied": "Angewandte Upgrades",
|
||||
"gameOver.stats_intro": "Hier findest du deine Spielstatistik im Vergleich zu Ihren {{count}} besten Spielen.",
|
||||
"gameOver.unlocked_perk": "Upgrade freigeschaltet",
|
||||
"gameOver.unlocked_perk_plural": "Du hast soeben {{count}} Vergünstigungen freigeschaltet",
|
||||
"gameOver.win.summary": "Das Spiel ist vorbei. Du hast {{score}} Münzen versteckt.",
|
||||
"gameOver.unlocked_perk_plural": "Du hast gerade {{count}} Vergünstigungen freigeschaltet",
|
||||
"gameOver.win.summary": "Das Spiel ist vorbei. Du hast {{score}} Münzen eingesteckt.",
|
||||
"gameOver.win.title": "Du hast dieses Spiel abgeschlossen",
|
||||
"history.columns.score": "Ergebnis",
|
||||
"help.content": "## Ziel\n\nSammle in 7 Levels so viele Münzen wie möglich ein.\nDie Münzen erscheinen, wenn du Ziegel zerbrichst.\nFangen Sie sie mit Ihrem Paddel auf, um Ihre Punktzahl zu erhöhen.\nIhr Punktestand wird in der oberen rechten Ecke des Bildschirms angezeigt.\nLassen Sie den Ball nicht fallen, sonst ist das Spiel vorbei.\n\nWenn du alle Ziegel zerstört hast, kannst du dir ein Upgrade aussuchen.\n\n## Upgrades\n\nDie Upgrades, die du wählst, gelten bis zum Ende des Laufs.\nEinige können mehrmals ausgewählt werden, um die Wirkung zu verstärken.\nEinige helfen beim Zielen oder machen das Spiel auf andere Weise einfacher.\nEinige sind nur in Kombination nützlich.\n\nZu Beginn eines jeden Spiels erhältst du immer ein Upgrade.\nIhr Symbol dient als Baustein des ersten Levels.\nDu kannst die Start-Upgrades in den Einstellungen auswählen.\n\nViele Upgrades wirken sich auf deine Kombo aus.\n\n## Combo\n\nDeine \"Combo\" ist die Anzahl der Münzen, die beim Zerbrechen eines Steins entstehen.\nSie wird auf deinem Paddel angezeigt, zum Beispiel x4 bedeutet, dass jeder Stein 4 Münzen hervorbringt.\nDie meisten Upgrades, die den Combo erhöhen, fügen auch eine Bedingung hinzu, um ihn zurückzusetzen.\nDie Kombo wird auch zurückgesetzt, wenn der Ball zum Schläger zurückkehrt, ohne einen Stein zu treffen.\nIn diesem Fall wird eine \"Miss\"-Meldung angezeigt.\n\nVersuchen Sie, jedes Mal auf einen Stein zu zielen.\n\n## Anvisieren\n\nNur die Position des Balls auf dem Schläger entscheidet darüber, wie der Ball abprallt.\nWenn der Ball das Paddel genau in der Mitte trifft, prallt er senkrecht nach oben ab.\nWenn du ihn mehr auf einer Seite triffst, hat er einen größeren Winkel.\nDie Paddelgeschwindigkeit und der Auftreffwinkel haben keinen Einfluss auf die Richtung des Balls nach dem Aufprall.\n\nViele Upgrades, die beim Zielen helfen, können freigeschaltet werden.\n\n## Freischaltungen\n\nWenn du Breakout 71 zum ersten Mal spielst, sind die meisten Upgrades und Levels gesperrt.\nUpgrades werden freigeschaltet, indem du einfach spielst und viele Münzen fängst.\nDie ersten Level werden durch das Erreichen einer hohen Punktzahl freigeschaltet.\nSpätere Levels fügen eine Bedingung hinzu, welche Vergünstigungen Sie auswählen können.\n\nEine hohe Punktzahl zu erreichen ist viel einfacher, wenn du nach jedem Level mehrere Upgrades erhältst.\n\n## Re-Rolls und kostenlose Upgrades\n\nWenn du gut spielst, bekommst du ein zusätzliches Upgrade, das du auswählen kannst:\n\n- Schaffe das Level in weniger als {{levelTimeGood}} Sekunden\n- Treffen Sie weniger als {{wallBouncedGood}} Mal die Seiten oder die Spitze\n- Fangen Sie {{catchRateGood}}% der Münzen\n- Verfehle die Steine weniger als {{missesGood}} Mal\n\nDu bekommst auch einen Re-Roll, mit dem du Upgrades überspringen kannst, wenn du noch besser abschneidest:\n\n- Schaffe ein Level in weniger als {{levelTimeBest}} Sekunden\n- Treffen Sie weniger als {{wallBouncedBest}} Mal die Seiten oder die Spitze\n- Fangen Sie {{catchRateBest}}% der Münzen\n- Verfehle die Steine weniger als {{missesBest}} Mal\n\nMit einer Option in den Einstellungen können Sie diese Statistiken anzeigen lassen",
|
||||
"help.help": "Erfahre mehr über das Spiel",
|
||||
"help.levels": "Level",
|
||||
"help.title": "Hilfe",
|
||||
"help.upgrades": "## Upgrades",
|
||||
"history.columns.score": "Punktzahl",
|
||||
"history.columns.started": "Datum",
|
||||
"history.help": "Sehen Sie Ihre {{count}} besten Spiele.",
|
||||
"history.locked": "Mindestens zehn Spiele spielen, um freizuschalten",
|
||||
"history.title": "Läuft Geschichte",
|
||||
"lab.help": "Versuchen Sie jede beliebige Konstruktion",
|
||||
"lab.instructions": "Wählen Sie unten die Upgrades aus und wählen Sie dann ein Level, das Sie spielen möchten.",
|
||||
"history.help": "Statistik deiner {{count}} besten Spiele.",
|
||||
"history.include_past_versions": "",
|
||||
"history.locked": "Spiele mindestens zehn Spiele spielen zum freizuschalten",
|
||||
"history.title": "Spielverlauf",
|
||||
"lab.help": "Probiere beliebige Konstruktionen aus",
|
||||
"lab.instructions": "Wähle Upgrades und ein Level aus und klicke darüber auf die Schaltfläche „Play“",
|
||||
"lab.menu_entry": "Kreativ-Modus",
|
||||
"lab.reset": "Alle auf 0 zurücksetzen",
|
||||
"lab.select_level": "Wählen Sie einen Level zum Spielen",
|
||||
"lab.unlocks_at": "Wird freigeschaltet bei Gesamtpunktzahl {{score}}",
|
||||
"level_up.after_buttons": "Du hast gerade Level {{level}}/{{max}}beendet.",
|
||||
"level_up.before_buttons": "Du hast {{score}} Münzen {{catchGain}} aus {{levelSpawnedCoins}} in {{time}} Sekunden {{timeGain}}gefangen.\n\nDu hast {{levelMisses}} Mal danebengeschossen {{missesGain}} und {{levelWallBounces}} Mal die Wände oder die Decke getroffen{{wallHitsGain}}.\n\n{{compliment}}",
|
||||
"lab.play": "Spielen",
|
||||
"lab.reset": "Zurücksetzen",
|
||||
"lab.select_level": "Wähle ein Level zum Spielen",
|
||||
"lab.unlocks_at": "Wird bei Gesamtpunktzahl {{score}} freigeschaltet",
|
||||
"level_up.after_buttons": "Du hast gerade Level {{level}}/{{max}} beendet.",
|
||||
"level_up.before_buttons": "Du hast {{score}} Münzen {{catchGain}} aus {{levelSpawnedCoins}} in {{time}} Sekunden {{timeGain}} gefangen.\n\nDu hast {{levelMisses}} Mal danebengeschossen {{missesGain}} und {{levelWallBounces}} Mal die Wände oder die Decke getroffen {{wallHitsGain}}.\n\n{{compliment}}",
|
||||
"level_up.compliment_advice": "Versuche, alle Münzen zu fangen, verpasse nie die Steine, stoße nie an die Wände/Decke oder schaffe das Level unter 30 Sekunden, um zusätzliche Upgrades zu erhalten.",
|
||||
"level_up.compliment_good": "Gut gemacht!",
|
||||
"level_up.compliment_perfect": "Beeindruckend, machen Sie weiter so!",
|
||||
"level_up.pick_upgrade_title": "Wählen Sie ein Upgrade",
|
||||
"level_up.plus_one_upgrade": "(+1 Aufwertung)",
|
||||
"level_up.plus_one_upgrade_and_reroll": "(+1 Aufwertung und +1 Neuwurf)",
|
||||
"level_up.plus_one_upgrade": "(+1 Upgrade)",
|
||||
"level_up.plus_one_upgrade_and_reroll": "(+1 Upgrade und +1 Neuwurf)",
|
||||
"level_up.reroll": "Neu würfeln ({{count}})",
|
||||
"level_up.reroll_help": "Neue Wahlmöglichkeiten bieten",
|
||||
"level_up.reroll_help": "Bietet neue Auswahl",
|
||||
"level_up.upgrade_perk_to_level": " lvl {{level}}",
|
||||
"main_menu.basic": "Grundlegende Grafiken",
|
||||
"main_menu.basic_help": "Bessere Leistung.",
|
||||
"main_menu.colorful_coins": "Bunte Münzen",
|
||||
"main_menu.colorful_coins_help": "Münzen spawnen immer in der Farbe des Steins",
|
||||
"main_menu.comboIncreaseTexts": "+X in Gold anzeigen",
|
||||
"main_menu.comboIncreaseTexts_help": "Wenn die Combo zunimmt",
|
||||
"main_menu.contrast": "Hoher Kontrast",
|
||||
"main_menu.contrast_help": "Buntes und dunkles Rendering",
|
||||
"main_menu.credit_levels": "Ebenen",
|
||||
"main_menu.donate": "Sie haben seit {{hours}} Stunden gespielt",
|
||||
"main_menu.basic": "",
|
||||
"main_menu.basic_help": "",
|
||||
"main_menu.colorful_coins": "",
|
||||
"main_menu.colorful_coins_help": "",
|
||||
"main_menu.comboIncreaseTexts": "",
|
||||
"main_menu.comboIncreaseTexts_help": "",
|
||||
"main_menu.contrast": "",
|
||||
"main_menu.contrast_help": "",
|
||||
"main_menu.credit_levels": "",
|
||||
"main_menu.donate": "Sie haben schon {{hours}} Stunden gespielt",
|
||||
"main_menu.donate_help": "Wie wäre es mit einer Spende? Sie können diese Erinnerung in den Einstellungen ausblenden.",
|
||||
"main_menu.donation_reminder": "Erinnern Sie mich an eine Spende",
|
||||
"main_menu.donation_reminder_help": "Siehe Spielzeit und Spendenlink im Hauptmenü",
|
||||
"main_menu.download_save_file": "Spielstand und Statistiken herunterladen",
|
||||
"main_menu.download_save_file_help": "Abrufen einer Speicherdatei",
|
||||
"main_menu.extra_bright": "Extra hell",
|
||||
"main_menu.extra_bright_help": "Erhöht die Größe des Halos um Münzen und Ziegel.",
|
||||
"main_menu.fullscreen": "Vollbild",
|
||||
"main_menu.fullscreen_help": "Das Spiel versucht, vor dem Start in den Vollbildmodus zu wechseln",
|
||||
"main_menu.help_content": "## Ziel\n\nSammle in 7 Levels so viele Münzen wie möglich ein.\nDie Münzen erscheinen, wenn du Ziegel zerbrichst.\nFangen Sie sie mit Ihrem Puck, um Ihre Punktzahl zu erhöhen.\nDein Punktestand wird in der oberen rechten Ecke des Bildschirms angezeigt.\nLassen Sie den Ball nicht fallen, sonst ist das Spiel vorbei.\n\nWenn du alle Ziegel zerstört hast, kannst du dir ein Upgrade aussuchen.\n\n## Upgrades\n\nDie Upgrades, die du wählst, gelten bis zum Ende des Laufs.\nEinige können mehrmals ausgewählt werden, um die Wirkung zu verstärken.\nEinige helfen beim Zielen oder machen das Spiel auf andere Weise einfacher.\nEinige sind nur in Kombination nützlich.\n\nZu Beginn eines jeden Spiels erhältst du immer ein Upgrade.\nIhr Symbol dient als Baustein für die erste Stufe.\nDu kannst die Start-Upgrades in den Einstellungen auswählen.\n\nViele Upgrades wirken sich auf deine Kombo aus.\n\n## Kombo\n\nDeine \"Combo\" ist die Anzahl der Münzen, die beim Zerbrechen eines Steins entstehen.\nSie wird auf deinem Puck angezeigt, z. B. x4 bedeutet, dass jeder Stein 4 Münzen hervorbringt.\nDie meisten Upgrades, die den Combo erhöhen, fügen auch eine Bedingung hinzu, um ihn zurückzusetzen.\nDie Kombo wird auch zurückgesetzt, wenn der Ball zum Puck zurückkehrt, ohne einen Stein zu treffen.\nWenn das passiert, wird eine \"Miss\"-Meldung angezeigt.\n\nVersuche, jedes Mal auf einen Stein zu zielen.\n\n## Anvisieren\n\nNur die Position des Balls auf dem Puck entscheidet darüber, wie er abprallen wird.\nWenn der Ball den Puck genau in der Mitte trifft, prallt er senkrecht nach oben zurück.\nWenn du ihn mehr auf einer Seite triffst, hat er einen größeren Winkel.\nDie Geschwindigkeit des Pucks und der Auftreffwinkel haben keinen Einfluss auf die Richtung des Balls nach dem Aufprall.\n\nViele Upgrades, die beim Zielen helfen, können freigeschaltet werden.\n\n## Freischaltungen\n\nWenn du Breakout 71 zum ersten Mal spielst, sind die meisten Upgrades und Levels gesperrt.\nUpgrades werden freigeschaltet, indem du einfach spielst und viele Münzen fängst.\nDie ersten Level werden durch das Erreichen einer hohen Punktzahl freigeschaltet.\nSpätere Levels fügen eine Bedingung hinzu, welche Vergünstigungen Sie auswählen können.\n\nEine hohe Punktzahl zu erreichen ist viel einfacher, wenn du nach jedem Level mehrere Upgrades erhältst.\n\n## Re-Rolls und kostenlose Upgrades\n\nDu bekommst ein zusätzliches Upgrade, wenn du gut spielst:\n\n- Schaffe das Level in weniger als {{levelTimeGood}} Sekunden\n- Treffen Sie weniger als {{wallBouncedGood}} Mal die Seiten oder die Spitze\n- Fangen Sie {{catchRateGood}}% der Münzen\n- Verfehle die Steine weniger als {{missesGood}} Mal\n\nDu bekommst auch einen Re-Roll, mit dem du Upgrades überspringen kannst, wenn du noch besser abschneidest:\n\n- Schaffe ein Level in weniger als {{levelTimeBest}} Sekunden\n- Treffen Sie weniger als {{wallBouncedBest}} Mal die Seiten oder die Spitze\n- Fangen Sie {{catchRateBest}}% der Münzen\n- Verfehle die Steine weniger als {{missesBest}} Mal\n\nMit einer Option in den Einstellungen können Sie diese Statistiken anzeigen lassen",
|
||||
"main_menu.help_help": "Erfahren Sie mehr über das Spiel",
|
||||
"main_menu.help_title": "Hilfe",
|
||||
"main_menu.help_upgrades": "## Upgrades",
|
||||
"main_menu.high_score": "Hohe Punktzahl : {{score}}",
|
||||
"main_menu.kid": "Kinder-Modus",
|
||||
"main_menu.kid_help": "Beginnen Sie künftige Spiele mit einem \"langsameren Ball\".",
|
||||
"main_menu.language": "Sprache",
|
||||
"main_menu.language_help": "Wählen Sie die Sprache des Spiels",
|
||||
"main_menu.load_save_file": "Speicherdatei laden",
|
||||
"main_menu.load_save_file_help": "Wählen Sie eine Speicherdatei auf Ihrem Gerät",
|
||||
"main_menu.max_coins": " {{max}} Münzen auf dem Bildschirm maximal",
|
||||
"main_menu.max_coins_help": "Nur kosmetisch, keine Auswirkung auf das Ergebnis",
|
||||
"main_menu.max_particles": " {{max}} Teilchen maximal",
|
||||
"main_menu.max_particles_help": "Begrenzt die Anzahl der auf dem Bildschirm angezeigten Partikel für visuelle Effekte.",
|
||||
"main_menu.mobile": "Mobiler Modus",
|
||||
"main_menu.mobile_help": "Lässt Raum unter dem Puck.",
|
||||
"main_menu.donation_reminder": "",
|
||||
"main_menu.donation_reminder_help": "",
|
||||
"main_menu.download_save_file": "",
|
||||
"main_menu.download_save_file_help": "",
|
||||
"main_menu.extra_bright": "",
|
||||
"main_menu.extra_bright_help": "",
|
||||
"main_menu.fullscreen": "",
|
||||
"main_menu.fullscreen_help": "",
|
||||
"main_menu.help_content": "",
|
||||
"main_menu.help_help": "",
|
||||
"main_menu.help_title": "",
|
||||
"main_menu.help_upgrades": "",
|
||||
"main_menu.high_score": "Höchstpunktzahl: {{score}}",
|
||||
"main_menu.kid": "",
|
||||
"main_menu.kid_help": "",
|
||||
"main_menu.language": "",
|
||||
"main_menu.language_help": "",
|
||||
"main_menu.load_save_file": "",
|
||||
"main_menu.load_save_file_help": "",
|
||||
"main_menu.max_coins": "",
|
||||
"main_menu.max_coins_help": "",
|
||||
"main_menu.max_particles": "",
|
||||
"main_menu.max_particles_help": "",
|
||||
"main_menu.mobile": "",
|
||||
"main_menu.mobile_help": "",
|
||||
"main_menu.normal": "Neues Spiel",
|
||||
"main_menu.normal_help": "Spiele 7 Levels mit einem zufälligen Startvorteil",
|
||||
"main_menu.pointer_lock": "Mauszeigersperre",
|
||||
"main_menu.pointer_lock_help": "Sperrt und versteckt den Mauszeiger.",
|
||||
"main_menu.record": "Spielvideos aufnehmen",
|
||||
"main_menu.record_download": "Video herunterladen ({{size}} MB)",
|
||||
"main_menu.record_help": "Holen Sie sich ein Video von jedem Level.",
|
||||
"main_menu.red_miss": "Miss Warnung",
|
||||
"main_menu.red_miss_help": "Zeigen Sie rote Partikel um Bälle, die ohne Treffer zu Boden gehen.",
|
||||
"main_menu.reset": "Spiel zurücksetzen",
|
||||
"main_menu.reset_cancel": "Nein",
|
||||
"main_menu.reset_confirm": "Ja",
|
||||
"main_menu.reset_help": "Löschen von Highscore, Spielzeit und Statistiken",
|
||||
"main_menu.reset_instruction": "Sie verlieren alle Fortschritte, die Sie im Spiel gemacht haben, sind Sie sicher?",
|
||||
"main_menu.save_file_error": "Fehler beim Laden einer Speicherdatei",
|
||||
"main_menu.save_file_loaded": "Geladene Datei speichern",
|
||||
"main_menu.save_file_loaded_help": "Die App wird nun neu geladen, um die Speicherung zu übernehmen.",
|
||||
"main_menu.save_file_loaded_ok": "Ok",
|
||||
"main_menu.settings_help": "Passen Sie das Spiel an Ihre Bedürfnisse und Ihren Geschmack an",
|
||||
"main_menu.pointer_lock": "",
|
||||
"main_menu.pointer_lock_help": "",
|
||||
"main_menu.record": "",
|
||||
"main_menu.record_download": "",
|
||||
"main_menu.record_help": "",
|
||||
"main_menu.red_miss": "",
|
||||
"main_menu.red_miss_help": "",
|
||||
"main_menu.reset": "",
|
||||
"main_menu.reset_cancel": "",
|
||||
"main_menu.reset_confirm": "",
|
||||
"main_menu.reset_help": "",
|
||||
"main_menu.reset_instruction": "",
|
||||
"main_menu.save_file_error": "",
|
||||
"main_menu.save_file_loaded": "",
|
||||
"main_menu.save_file_loaded_help": "",
|
||||
"main_menu.save_file_loaded_ok": "",
|
||||
"main_menu.settings_help": "Passe das Spiel an deine Bedürfnisse und deinen Geschmack an",
|
||||
"main_menu.settings_title": "Einstellungen",
|
||||
"main_menu.show_fps": "FPS-Zähler",
|
||||
"main_menu.show_fps_help": "Überwachen Sie die Leistung der Anwendung",
|
||||
"main_menu.show_stats": "Echtzeit-Statistiken anzeigen",
|
||||
"main_menu.show_stats_help": "Münzen, Zeit, Sprünge, Fehlschüsse",
|
||||
"main_menu.sounds": "Spiel-Sounds",
|
||||
"main_menu.sounds_help": "Kann einige Telefone verlangsamen.",
|
||||
"main_menu.starting_perks": "Startvorteile",
|
||||
"main_menu.starting_perks_checked": "Wenn Sie ein neues Spiel beginnen, wird Ihnen eine dieser Vergünstigungen angeboten. Klicken Sie auf eine Vergünstigung, um sie auszuschließen.",
|
||||
"main_menu.starting_perks_full_random": "Alle Vorteile wurden entfernt, die Auswahl erfolgt nach dem Zufallsprinzip.",
|
||||
"main_menu.starting_perks_help": "Wählen Sie mögliche Start-Upgrades",
|
||||
"main_menu.starting_perks_unchecked": "Die folgenden Vergünstigungen werden nicht als Startvergünstigungen angeboten, aber Sie können sie durch Anklicken zum Pool hinzufügen.",
|
||||
"main_menu.show_fps": "",
|
||||
"main_menu.show_fps_help": "",
|
||||
"main_menu.show_stats": "",
|
||||
"main_menu.show_stats_help": "",
|
||||
"main_menu.sounds": "",
|
||||
"main_menu.sounds_help": "",
|
||||
"main_menu.starting_perks": "",
|
||||
"main_menu.starting_perks_checked": "",
|
||||
"main_menu.starting_perks_full_random": "",
|
||||
"main_menu.starting_perks_help": "",
|
||||
"main_menu.starting_perks_unchecked": "",
|
||||
"main_menu.title": "Breakout 71",
|
||||
"main_menu.unlocks": "Freigegebene Inhalte",
|
||||
"main_menu.unlocks_help": "Freigegebene Vergünstigungen und Stufen ausprobieren",
|
||||
"play.close_modale_window_tooltip": "Schließen Sie",
|
||||
"play.current_lvl": "Stufe {{level}}/{{max}}",
|
||||
"main_menu.unlocks": "Freischaltete Inhalte",
|
||||
"main_menu.unlocks_help": "Freigeschaltete Vergünstigungen und Stufen ausprobieren",
|
||||
"play.close_modale_window_tooltip": "Schließen",
|
||||
"play.current_lvl": "Level {{level}}/{{max}}",
|
||||
"play.menu_label": "Menu",
|
||||
"play.menu_tooltip": "Hauptmenü öffnen",
|
||||
"play.missed_ball": "Miss",
|
||||
"play.mobile_press_to_play": "Zum Abspielen hier drücken und halten",
|
||||
"play.missed_ball": "Verstecken",
|
||||
"play.mobile_press_to_play": "Zum Spielen hier gedrückt halten",
|
||||
"play.score_tooltip": "Sehen Sie Ihren Punktestand, Upgrades und mehr",
|
||||
"play.stats.coins_catch_rate": "Fangrate der Münzen",
|
||||
"play.stats.levelMisses": "Verfehlte Schüsse, bei denen man nichts trifft",
|
||||
"play.stats.levelTime": "Level Zeit",
|
||||
"play.stats.levelWallBounces": "Mauervorsprünge",
|
||||
"score_panel.close_to_unlock": "Nächste Stufe freischalten:",
|
||||
"score_panel.get_upgrades_to_unlock": "Holen Sie {{missingUpgrades}} und erzielen Sie {{points}} mehr Punkte, um Level \"{{level}}\" freizuschalten. \"",
|
||||
"score_panel.rerolls_count": "Sie haben {{rerolls}} Wiederholungswürfe angesammelt",
|
||||
"score_panel.score_to_unlock": "Erziele {{points}} mehr Punkte, um Level \"{{level}}\" freizuschalten. \"",
|
||||
"score_panel.title": "{{score}} Punkte auf Stufe {{level}}/{{max}} ",
|
||||
"score_panel.upcoming_levels": "Kommende Stufen :",
|
||||
"score_panel.upgrades_picked": "Die in diesem Spiel gewählten Upgrades laufen:",
|
||||
"unlocks.greyed_out_help": "Die ausgegrauten Upgrades können freigeschaltet werden, indem Sie Ihre Gesamtpunktzahl erhöhen. Die Gesamtpunktzahl erhöht sich jedes Mal, wenn Sie im Spiel punkten.",
|
||||
"unlocks.intro": "Deine Gesamtpunktzahl ist {{ts}}. Nachfolgend finden Sie alle Upgrades und Levels, die das Spiel zu bieten hat. Klicken Sie auf ein Upgrade oder eine Stufe, um ein Testspiel damit zu starten.",
|
||||
"play.stats.levelMisses": "Verfehlte Schüsse, bei denen du nichts getroffen hast",
|
||||
"play.stats.levelTime": "Zeit pro Level",
|
||||
"play.stats.levelWallBounces": "Wandaufpralle",
|
||||
"score_panel.close_to_unlock": "Nächstes Level freischalten:",
|
||||
"score_panel.get_upgrades_to_unlock": "Hole {{missingUpgrades}} und erziele {{points}} mehr Punkte, um Level \"{{level}}\" freizuschalten.",
|
||||
"score_panel.rerolls_count": "Du hast {{rerolls}} Upgrades neugewürfelt",
|
||||
"score_panel.score_to_unlock": "Erziele {{points}} mehr Punkte, um Level \"{{level}}\" freizuschalten.",
|
||||
"score_panel.title": "{{score}} Punkte in Level {{level}}/{{max}} ",
|
||||
"score_panel.upcoming_levels": "Kommende Level:",
|
||||
"score_panel.upgrades_picked": "In diesem Spiel freigeschaltete Upgrades:",
|
||||
"settings.autoplay": "Automatisch spielen",
|
||||
"settings.autoplay_help": "Starte eine Sitzung mit zufälligen Upgrades und einem computergesteuerten Paddel",
|
||||
"settings.basic": "Einfache Grafik",
|
||||
"settings.basic_help": "Bessere Leistung",
|
||||
"settings.colorful_coins": "Bunte Münzen",
|
||||
"settings.colorful_coins_help": "Münzen spawnen immer in der Farbe des Steins",
|
||||
"settings.comboIncreaseTexts": "+X golden anzeigen",
|
||||
"settings.comboIncreaseTexts_help": "Wenn die Combo zunimmt",
|
||||
"settings.contrast": "Hoher Kontrast",
|
||||
"settings.contrast_help": "Buntes und dunkles Rendering",
|
||||
"settings.donation_reminder": "Erinnere mich an eine Spende",
|
||||
"settings.donation_reminder_help": "Siehe Spielzeit und Spendenlink im Hauptmenü",
|
||||
"settings.download_save_file": "Spielstand und Statistiken herunterladen",
|
||||
"settings.download_save_file_help": "Abrufen einer Speicherdatei",
|
||||
"settings.extra_bright": "Extra hell",
|
||||
"settings.extra_bright_help": "Erhöht die Größe des Halos um Münzen und Ziegel.",
|
||||
"settings.fullscreen": "Vollbild",
|
||||
"settings.fullscreen_help": "Das Spiel versucht, vor dem Start in den Vollbildmodus zu wechseln",
|
||||
"settings.kid": "Kinder-Modus",
|
||||
"settings.kid_help": "Beginne künftige Spiele mit \"langsameren Ball\".",
|
||||
"settings.language": "Sprache",
|
||||
"settings.language_help": "Wähle die Sprache des Spiels",
|
||||
"settings.load_save_file": "Speicherdatei laden",
|
||||
"settings.load_save_file_help": "Wähle eine Speicherdatei auf Ihrem Gerät",
|
||||
"settings.max_coins": " {{max}} Münzen auf dem Bildschirm maximal",
|
||||
"settings.max_coins_help": "Nur kosmetisch, keine Auswirkung auf die Punktzahl",
|
||||
"settings.mobile": "Handy-Modus",
|
||||
"settings.mobile_help": "Lässt Platz unter dem Paddel.",
|
||||
"settings.pointer_lock": "Mauszeigersperre",
|
||||
"settings.pointer_lock_help": "Sperrt und versteckt den Mauszeiger.",
|
||||
"settings.precise_lighting": "Präzise Beleuchtung",
|
||||
"settings.precise_lighting_help": "Verwenden Sie ein kleineres Raster für den Hintergrundlichteffekt",
|
||||
"settings.probabilistic_lighting": "Persistenz des Sehens",
|
||||
"settings.probabilistic_lighting_help": "Verbessern Sie die Leistung, wenn mehr als 150 Münzen vorhanden sind, indem Sie einen Teil des Lichts des vorherigen Frames wiederverwenden",
|
||||
"settings.record": "Spielvideos aufnehmen",
|
||||
"settings.record_download": "Video herunterladen ({{size}} MB)",
|
||||
"settings.record_help": "Bekomme ein Video von jedem Level.",
|
||||
"settings.red_miss": "Verstecke Warnung",
|
||||
"settings.red_miss_help": "Zeige rote Partikel um Bälle, die ohne Treffer zu Boden gehen.",
|
||||
"settings.reset": "Spiel zurücksetzen",
|
||||
"settings.reset_cancel": "Nein",
|
||||
"settings.reset_confirm": "Ja",
|
||||
"settings.reset_help": "Löschen von Highscore, Spielzeit und Statistiken",
|
||||
"settings.reset_instruction": "Du verlierst alle Fortschritte, die du im Spiel gemacht hast, bist du dir sicher?",
|
||||
"settings.save_file_error": "Fehler beim Laden einer Speicherdatei",
|
||||
"settings.save_file_loaded": "Geladene Datei speichern",
|
||||
"settings.save_file_loaded_help": "Die App wird nun neu geladen, um die Speicherung zu übernehmen.",
|
||||
"settings.save_file_loaded_ok": "Ok",
|
||||
"settings.show_fps": "FPS-Zähler",
|
||||
"settings.show_fps_help": "Überwache die Leistung der Anwendung",
|
||||
"settings.show_stats": "Echtzeit-Statistiken anzeigen",
|
||||
"settings.show_stats_help": "Münzen, Zeit, Sprünge, Verfehlungen",
|
||||
"settings.smooth_lighting": "Sanfte Beleuchtung",
|
||||
"settings.smooth_lighting_help": "Verwische die Lichteffekte im Hintergrund, damit sie weniger quadratisch aussehen. Erhöht die Verzögerung.",
|
||||
"settings.sounds": "Spiel-Geräusche",
|
||||
"settings.sounds_help": "Piepsen, Bloops und Brrrr",
|
||||
"settings.stress_test": "Stresstest",
|
||||
"settings.stress_test_help": "Starte ein Bot-gesteuertes Spiel mit einer sehr hohen Anzahl an Münzen, um die Leistungsgrenzen deines Geräts zu testen.",
|
||||
"starting_perks.checked": "Wenn du ein neues Spiel beginnst, wird dir eine dieser Vergünstigungen angeboten. Klicke auf eine Vergünstigung, um sie auszuschließen.",
|
||||
"starting_perks.help": "Wähle mögliche Start-Upgrades",
|
||||
"starting_perks.random": "Alle Vorteile wurden entfernt, die Auswahl erfolgt nach dem Zufallsprinzip.",
|
||||
"starting_perks.title": "Startvorteile",
|
||||
"starting_perks.unchecked": "Die folgenden Vergünstigungen werden nicht als Startvergünstigungen angeboten, aber du kannst sie durch Anklicken zum Pool hinzufügen.",
|
||||
"unlocks.greyed_out_help": "Die ausgegrauten Upgrades können freigeschaltet werden, indem du Ihre Gesamtpunktzahl erhöhst. Die Gesamtpunktzahl erhöht sich jedes Mal, wenn du im Spiel punktest.",
|
||||
"unlocks.intro": "Deine Gesamtpunktzahl ist {{ts}}. Nachfolgend findest du alle Upgrades und Levels, die das Spiel zu bieten hat. Klicke auf ein Upgrade oder eine Stufe, um ein Testspiel damit zu starten.",
|
||||
"unlocks.just_unlocked": "Level freigeschaltet",
|
||||
"unlocks.just_unlocked_plural": "Du hast soeben {{count}} Stufen freigeschaltet",
|
||||
"unlocks.level": "<h2>Du hast {{unlocked}} Stufen von {{out_of}}freigeschaltet </h2>\n<p>Hier sind alle Spielstufen, klicke eine an, um sie auszuprobieren.</p> ",
|
||||
"unlocks.just_unlocked_plural": "Du hast gerade {{count}} Stufen freigeschaltet",
|
||||
"unlocks.level": "<h2>Du hast {{unlocked}} Stufen von {{out_of}} freigeschaltet </h2>\n<p>Hier sind alle Level des Spiels, klicke eins an, um es auszuprobieren.</p> ",
|
||||
"unlocks.level_description": "Ein {{size}}x{{size}} Level mit {{bricks}} Steinen, {{colors}} Farben und {{bombs}} Bomben.",
|
||||
"unlocks.minScore": "Erreiche ${{minScore}} in einem Lauf, um freizuschalten.",
|
||||
"unlocks.minScoreWithPerks": "Erreiche ${{minScore}} in einem Durchgang mit {{required}} , aber ohne {{forbidden}} zu entsperren.",
|
||||
"unlocks.minTotalScore": "Kumulieren Sie insgesamt ${{score}}",
|
||||
"unlocks.reached": "Ihr bestes Ergebnis war {{reached}}.",
|
||||
"unlocks.title_upgrades": "Du hast {{unlocked}} Upgrades von {{out_of}}freigeschaltet.",
|
||||
"unlocks.levels": "",
|
||||
"unlocks.minScore": "Erreiche ${{minScore}} in einem Lauf zum freischalten.",
|
||||
"unlocks.minScoreWithPerks": "Erreiche ${{minScore}} in einem Spiel mit {{required}} , aber ohne {{forbidden}} freizuschalten.",
|
||||
"unlocks.minTotalScore": "Summiert ein Punktstand von ${{score}}",
|
||||
"unlocks.reached": "Ihr bester Punktstand war {{reached}}.",
|
||||
"unlocks.title_upgrades": "Du hast {{unlocked}} Upgrades von {{out_of}} freigeschaltet.",
|
||||
"unlocks.upgrades": "",
|
||||
"upgrades.addiction.name": "Sucht",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} Combo / Stein, Combo wird {{delay}}s nach Zerbrechen eines Steins zurückgesetzt.",
|
||||
"upgrades.addiction.verbose_description": "Der Countdown beginnt erst nach dem Zerbrechen des ersten Steins eines jeden Levels. Er stoppt, sobald alle Ziegel zerstört sind.",
|
||||
|
@ -167,28 +263,40 @@
|
|||
"upgrades.bigger_explosions.name": "Kaboom",
|
||||
"upgrades.bigger_explosions.tooltip": "Größere Explosionen",
|
||||
"upgrades.bigger_explosions.verbose_description": "Die Standardexplosion räumt ein 3x3-Quadrat, mit dieser wird es zu einem 5x5-Quadrat, und der Schlag auf die Münzen ist auch wesentlich stärker. Der Bildschirm blinkt nach jeder Explosion (außer im Basismodus)",
|
||||
"upgrades.bigger_puck.name": "Größerer Puck",
|
||||
"upgrades.bigger_puck.name": "Größeres Paddel",
|
||||
"upgrades.bigger_puck.tooltip": "Einfach mehr Münzen fangen.",
|
||||
"upgrades.bigger_puck.verbose_description": "Ein größerer Puck macht es einfacher, den Ball nie zu verfehlen und mehr Münzen zu fangen. Außerdem kann man die Abpraller genau ausrichten (der Winkel des Balls hängt nur davon ab, wo er den Puck trifft).\n\nAllerdings ist es mit einem großen Puck schwieriger, die Seiten des Levels zu umspielen, so dass es manchmal unvermeidlich ist, den Ball zu verfehlen.",
|
||||
"upgrades.bigger_puck.verbose_description": "Ein größeres Paddel macht es einfacher, den Ball nie zu verfehlen und mehr Münzen zu fangen. Außerdem kann man die Abpraller genau ausrichten (der Winkel des Balls hängt nur davon ab, wo er das Paddel trifft).",
|
||||
"upgrades.bricks_attract_ball.name": "Ziegelsteine ziehen Bälle an",
|
||||
"upgrades.bricks_attract_ball.tooltip": "Der Ball fliegt zu den ersten {{count}} Steinen, die er trifft.",
|
||||
"upgrades.bricks_attract_ball.verbose_description": "Die Wirkung ist bei höheren Stufen stärker. Die Anzahl der Steine, die getroffen werden können, bevor der Effekt aufhört, ist ebenfalls höher. Der Effekt setzt wieder ein, wenn der Ball den Puck trifft.",
|
||||
"upgrades.bricks_attract_coins.name": "Ziegelsteine ziehen Münzen an",
|
||||
"upgrades.bricks_attract_coins.tooltip": "Hilft ihnen, dort oben zu bleiben",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "Boje",
|
||||
"upgrades.buoy.tooltip": "Münzen schweben {{duration}} Sekunden lang auf der unteren Linie.",
|
||||
"upgrades.buoy.verbose_description": "Der Effekt ist im mobilen Modus am deutlichsten sichtbar",
|
||||
"upgrades.clairvoyant.name": "Hellsichtig",
|
||||
"upgrades.clairvoyant.tooltip": "Sehen Sie die nächsten Levels, die HP der Steine und die Ballrichtung",
|
||||
"upgrades.clairvoyant.verbose_description": "Hilft dir, die richtigen Upgrades auszuwählen und zu verstehen, was es mit den robusten Steinen auf sich hat. Level 2 und 3 bringen zusätzliches Wissen von zweifelhaftem Nutzen (erreichbar im Loop-Modus)",
|
||||
"upgrades.coin_magnet.help_plural": "Stärkere Wirkung auf die Münzen",
|
||||
"upgrades.coin_magnet.name": "Magnet für Münzen",
|
||||
"upgrades.coin_magnet.tooltip": "Puck zieht Münzen an",
|
||||
"upgrades.coin_magnet.verbose_description": "Lenkt die Münzen auf den Puck. Der Effekt ist stärker, wenn die Münze bereits in der Nähe ist. Alle Münzen zu fangen, bringt besondere Boni im Spiel.\n\nEine andere Möglichkeit, mehr Münzen zu fangen, besteht darin, Ziegelsteine von unten zu treffen. Die Geschwindigkeit und die Richtung des Balls beeinflussen die Geschwindigkeit der Münzen, die auftauchen.",
|
||||
"upgrades.coin_magnet.tooltip": "Paddel zieht Münzen an",
|
||||
"upgrades.coin_magnet.verbose_description": "Lenkt die Münzen auf das Paddel. Der Effekt ist stärker, wenn die Münze bereits in der Nähe ist.",
|
||||
"upgrades.compound_interest.name": "Zinseszins",
|
||||
"upgrades.compound_interest.tooltip": "+{{lvl}} Combo pro zerbrochenem Stein, Rücksetzung bei verlorener Münze",
|
||||
"upgrades.compound_interest.verbose_description": "Mit jedem Ziegelstein, den du zerbrichst, wächst deine Combo um einen Ziegelstein, und mit jedem Ziegelstein, den du zerbrichst, erhältst du mehr und mehr Münzen.\n\nAchte jedoch darauf, jede dieser Münzen mit deinem Puck zu fangen, da jede verlorene Münze deine Kombo zurücksetzt.\n\nSobald deine Kombo über dem Minimum liegt, erscheint am unteren Rand des Spielfelds eine rote Linie, die dich daran erinnert, dass die Münzen nicht dorthin gelangen sollten.",
|
||||
"upgrades.concave_puck.name": "Konkaver Puck",
|
||||
"upgrades.compound_interest.verbose_description": "Deine Combo wächst jedes Mal um eins, wenn du einen Stein zerbrichst, und bringt mit jedem Stein, den du zerbrichst, mehr und mehr Münzen hervor.\nAchten Sie jedoch darauf, jede dieser Münzen mit Ihrem Paddel aufzufangen, da jede verlorene Münze Ihre Combo zurücksetzt.\nSobald deine Kombo über dem Minimum liegt, wird der Boden des Spielfelds mit einer roten Linie markiert, um dich daran zu erinnern, dass die Münzen nicht dorthin gehören.",
|
||||
"upgrades.concave_puck.name": "Konkaves Paddel",
|
||||
"upgrades.concave_puck.tooltip": "Verbessert die vertikale Zielgenauigkeit",
|
||||
"upgrades.concave_puck.verbose_description": "Die Bälle gehen zu Beginn des Levels gerade nach oben und prallen in einem geringeren Winkel ab.",
|
||||
"upgrades.corner_shot.name": "Eckball",
|
||||
"upgrades.corner_shot.tooltip": "Lässt deinen Puck mit den Rändern des Bildschirms überlappen",
|
||||
"upgrades.corner_shot.tooltip": "Lässt Ihr Paddel mit den Rändern des Bildschirms überlappen",
|
||||
"upgrades.corner_shot.verbose_description": "Hilft beim Zielen in den Kurven. Weitere Stufen lassen Sie weiter hinausgehen.",
|
||||
"upgrades.double_or_nothing.name": "",
|
||||
"upgrades.double_or_nothing.tooltip": "",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "Münzen, im Weltraum",
|
||||
"upgrades.etherealcoins.tooltip": "Münzen werden nicht mehr von der Schwerkraft beeinflusst",
|
||||
"upgrades.etherealcoins.verbose_description": "",
|
||||
"upgrades.etherealcoins.verbose_description": "Die Münzen behalten ihre Geschwindigkeit auch nach mehreren Aufprallvorgängen bei und werden nicht mehr durch die Schwerkraft beeinflusst.",
|
||||
"upgrades.extra_levels.name": "5 min mehr",
|
||||
"upgrades.extra_levels.tooltip": "Spielen Sie {{count}} Stufen statt 7",
|
||||
"upgrades.extra_levels.verbose_description": "Das Standardspiel kann maximal 7 Stufen dauern, danach ist das Spiel vorbei.\n\nMit jeder Stufe dieses Vorteils können Sie eine Stufe höher gehen. Die letzten Level sind oft diejenigen, in denen man die meisten Punkte macht, so dass der Unterschied dramatisch sein kann.",
|
||||
|
@ -205,17 +313,23 @@
|
|||
"upgrades.ghost_coins.name": "Geistermünzen",
|
||||
"upgrades.ghost_coins.tooltip": "Münzen gehen langsam durch Ziegelsteine",
|
||||
"upgrades.ghost_coins.verbose_description": "Das ist kein Bug, sondern ein Feature! Die Münzen fliegen nur langsam durch die Ziegel. Höhere Stufen lassen sie schneller fliegen.",
|
||||
"upgrades.happy_family.name": "",
|
||||
"upgrades.happy_family.tooltip": "",
|
||||
"upgrades.happy_family.verbose_description": "",
|
||||
"upgrades.helium.name": "Helium",
|
||||
"upgrades.helium.tooltip": "Umgekehrte Schwerkraft links und rechts vom Puck",
|
||||
"upgrades.helium.tooltip": "Umgekehrte Schwerkraft links und rechts des Paddels",
|
||||
"upgrades.helium.verbose_description": "Dies wirkt sich auf die Münzen aus und lässt sie nach oben treiben, bis Sie bereit sind, sie aufzuheben.",
|
||||
"upgrades.hot_start.name": "Heißer Start",
|
||||
"upgrades.hot_start.tooltip": "Start bei Kombo {{start}}, -{{loss}} Kombo pro Sekunde",
|
||||
"upgrades.hot_start.verbose_description": "Zu Beginn eines jeden Levels beginnt deine Kombo mit +30 Punkten, aber dann wird sie jede Sekunde um einen Punkt verringert. Der Effekt ist mit anderen Perks stapelbar.",
|
||||
"upgrades.hypnosis.name": "Hypnose",
|
||||
"upgrades.hypnosis.tooltip": "Immer wenn ein Ziegelstein seine Farbe ändert, teleportierst du diese Münze zur nächsten Kugel und lädst ihre Fähigkeit, einen Ziegelstein zu färben, wieder auf.",
|
||||
"upgrades.hypnosis.verbose_description": "",
|
||||
"upgrades.implosions.name": "Implosionen",
|
||||
"upgrades.implosions.tooltip": "Explosionen saugen Münzen an, anstatt sie wegzublasen",
|
||||
"upgrades.implosions.verbose_description": "Die Explosionskraft wird in die andere Richtung angewendet. Weitere Stufen wirken als \"größere Explosion\".",
|
||||
"upgrades.instant_upgrade.name": "Sofortiges Upgrade",
|
||||
"upgrades.instant_upgrade.tooltip": "+1 Upgrade jetzt, -1 Wahl bis Spielende.",
|
||||
"upgrades.instant_upgrade.tooltip": "+2 Aufwertung jetzt, -1 Wahl bis Spielende.",
|
||||
"upgrades.instant_upgrade.verbose_description": "Wählen Sie sofort zwei Upgrades aus, so dass Sie ein kostenloses Upgrade erhalten und eines, mit dem Sie das Upgrade, mit dem Sie diese Vergünstigung erhalten haben, zurückzahlen. Bei jedem weiteren Menü zur Auswahl von Upgrades gibt es weniger Optionen zur Auswahl.",
|
||||
"upgrades.left_is_lava.name": "Linke Seite meiden",
|
||||
"upgrades.left_is_lava.tooltip": "+{{lvl}} Combo pro zerbrochenem Stein. Combo wird zurückgesetzt, wenn der Ball die linke Seite des Bildschirms trifft.",
|
||||
|
@ -225,7 +339,7 @@
|
|||
"upgrades.limitless.verbose_description": "Durch die Wahl dieses Vorteils wird auch sein eigenes Limit um eins erhöht, so dass man es erneut wählen kann.",
|
||||
"upgrades.metamorphosis.name": "Metamorphose",
|
||||
"upgrades.metamorphosis.tooltip": "Jede Münze kann {{lvl}} Steine mit ihrer Farbe färben",
|
||||
"upgrades.metamorphosis.verbose_description": "Mit diesem Vorteil haben die Münzen die Farbe des Steins, aus dem sie stammen, und färben den ersten Stein, den sie berühren, in derselben Farbe.\n\nMünzen spawnen mit der Geschwindigkeit des Balls, der sie zerbrochen hat, was bedeutet, dass du ein bisschen in die Richtung der Ziegelsteine zielen kannst, die du \"malen\" willst.",
|
||||
"upgrades.metamorphosis.verbose_description": "Mit diesem Vorteil haben die Münzen die Farbe des Ziegels, aus dem sie stammen, und färben den ersten Ziegel, den sie berühren, in derselben Farbe. Die Münzen spawnen mit der Geschwindigkeit des Balls, der sie zerbrochen hat, was bedeutet, dass du ein bisschen in die Richtung der Ziegelsteine zielen kannst, die du \"anmalen\" willst. Auf Stufe 1 kann jede Münze 1 Ziegelstein einfärben, bevor sie \"verbraucht\" wird und hohl erscheint.",
|
||||
"upgrades.minefield.name": "Minenfeld",
|
||||
"upgrades.minefield.tooltip": "+{{lvl}} Kombo pro Bombenstein auf dem Bildschirm",
|
||||
"upgrades.minefield.verbose_description": "Fügt +lvl zur Combo hinzu, wenn ein Ziegelstein platziert wird, -lvl, wenn er zerstört wird, und erhöht die Basiskombo um die Anzahl der Ziegelsteine mal lvl",
|
||||
|
@ -233,27 +347,33 @@
|
|||
"upgrades.multiball.tooltip": "Beginne jedes Level mit {{count}} Bällen.",
|
||||
"upgrades.multiball.verbose_description": "Sobald du den Ball in Breakout 71 fallen lässt, hast du verloren.\n\nMit diesem Vorteil erhalten Sie zwei Bälle und können es sich daher leisten, einen zu verlieren.\n\nDie verlorenen Bälle kommen im nächsten Level zurück.\n\nWenn du mehr als einen Ball hast, stehen dir weitere Vergünstigungen zur Verfügung, und du kannst das Level natürlich schneller abschließen.",
|
||||
"upgrades.nbricks.name": "Strenger Stichprobenumfang",
|
||||
"upgrades.nbricks.tooltip": "Triff genau {{lvl}} Steine pro Puckaufprall für +{{lvl}} Combo, sonst wird er zurückgesetzt",
|
||||
"upgrades.nbricks.tooltip": "Triff genau {{lvl}} Steine pro Paddle Bounce für +{{lvl}} Combo, sonst wird er zurückgesetzt",
|
||||
"upgrades.nbricks.verbose_description": "Ihr müsst die Steine nicht unbedingt zerstören, aber ihr müsst sie treffen. Durch Explosionen zerstörte Ziegelsteine zählen nicht.",
|
||||
"upgrades.one_more_choice.name": "Extra Auswahl",
|
||||
"upgrades.one_more_choice.tooltip": "Weitere Stufenaufstiege bieten {{lvl}} weitere Option(en) in der Liste",
|
||||
"upgrades.one_more_choice.verbose_description": "Jedes Upgrade-Menü wird eine weitere Option enthalten. Erhöht nicht die Anzahl der Upgrades, die Sie auswählen können.",
|
||||
"upgrades.ottawa_treaty.name": "Ottawa-Vertrag",
|
||||
"upgrades.ottawa_treaty.tooltip": "Das Zerschlagen eines Ziegelsteins in der Nähe einer Bombe entschärft diese",
|
||||
"upgrades.ottawa_treaty.verbose_description": "Die nahe Bombe wird durch einen farbigen Block ersetzt. Wenn du einen Pionier hast, verliert der Ball seinen Pioniereffekt bis zum nächsten Aufprall. Es kann immer nur eine Bombe ersetzt werden.",
|
||||
"upgrades.passive_income.name": "Passives Einkommen",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} Combo / Brick, es sei denn, der Puck hat sich in den letzten {{time}}s bewegt, dann wird er stattdessen zurückgesetzt",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} Combo / Brick, es sei denn, das Paddel hat sich in den letzten {{time}}s bewegt, dann wird es stattdessen zurückgesetzt",
|
||||
"upgrades.passive_income.verbose_description": "Einige Vergünstigungen können den Bällen helfen, das zu tun, was du willst, ohne dass du etwas tun musst.",
|
||||
"upgrades.picky_eater.name": "Wählerischer Esser",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} Combo pro zerbrochenem Stein, wird bei Farbwechsel des Balls zurückgesetzt",
|
||||
"upgrades.picky_eater.verbose_description": "Jedes Mal, wenn du einen Stein der gleichen Farbe wie deine Kugel zerstörst, erhöht sich deine Kombination um eins.\nWenn es eine andere Farbe ist, nimmt der Ball diese neue Farbe an, aber die Kombination wird zurückgesetzt, es sei denn, es sind keine Steine in der Farbe des Balls übrig.\nSobald du eine höhere Kombination als das Minimum erreicht hast, werden die Steine der falschen Farbe rot umrandet.\nWenn du mehr als eine Kugel hast, wechseln sie alle die Farbe, sobald eine von ihnen einen Stein trifft.",
|
||||
"upgrades.pierce.name": "Piercing",
|
||||
"upgrades.pierce.tooltip": "Ball durchdringt {{count}} Steine nach einem Puckabprall",
|
||||
"upgrades.pierce.verbose_description": "Der Ball prallt normalerweise ab, sobald er etwas berührt. Mit diesem Vorteil setzt er seine Flugbahn für bis zu 3 Ziegelsteine gebrochen fort.\n\nDanach prallt er am 4. Ziegelstein ab, und du musst den Puck berühren, um den Zähler zurückzusetzen.",
|
||||
"upgrades.pierce.tooltip": "Der Ball durchdringt {{count}} Steine nach einem Paddle Bounce",
|
||||
"upgrades.pierce.verbose_description": "Der Ball prallt normalerweise ab, sobald er etwas berührt. Mit diesem Vorteil setzt er seine Flugbahn für bis zu 3 Ziegelsteine gebrochen fort.\n\nDanach prallt er am 4. Ziegelstein ab, und du musst das Paddel berühren, um den Zähler zurückzusetzen.",
|
||||
"upgrades.pierce_color.name": "Farbe durchstechen",
|
||||
"upgrades.pierce_color.tooltip": "+{{lvl}} Schaden an Steinen der Farbe der Kugel",
|
||||
"upgrades.pierce_color.verbose_description": "Wenn ein Ball auf einen gleichfarbigen Stein trifft, geht er ungehindert durch.\n\nSobald er einen andersfarbigen Stein erreicht, zerbricht er ihn, nimmt seine Farbe an und springt auf.\n\nWenn du robuste Steine hast, kann es sein, dass der Ball trotzdem an einem gleichfarbigen Stein abprallt.",
|
||||
"upgrades.puck_repulse_ball.help_plural": "Die Abstoßungskraft ist größer",
|
||||
"upgrades.puck_repulse_ball.help_plural": "Stärkere Abstoßungskraft",
|
||||
"upgrades.puck_repulse_ball.name": "Weiche Landung",
|
||||
"upgrades.puck_repulse_ball.tooltip": "Puck stößt Bälle ab",
|
||||
"upgrades.puck_repulse_ball.verbose_description": "Wenn ein Ball in die Nähe des Pucks kommt, wird er langsamer und springt möglicherweise sogar ab, ohne den Puck zu berühren.",
|
||||
"upgrades.puck_repulse_ball.tooltip": "Paddel stößt Bälle ab",
|
||||
"upgrades.puck_repulse_ball.verbose_description": "Wenn ein Ball in die Nähe des Schlägers kommt, wird er langsamer und springt möglicherweise sogar, ohne den Schläger zu berühren.",
|
||||
"upgrades.rainbow.name": "Regenbogen",
|
||||
"upgrades.rainbow.tooltip": "Münzen spawnen in Regenbogenfarben.",
|
||||
"upgrades.rainbow.verbose_description": "Mit jedem Level steigt der Anteil der farbigen Münzen. Die Farbe hängt von der Levelzeit ab.",
|
||||
"upgrades.reach.name": "Von oben nach unten",
|
||||
"upgrades.reach.tooltip": " Das Berühren der N Steine der untersten Reihe setzt die Kombo zurück. Andernfalls: +N Combo",
|
||||
"upgrades.reach.verbose_description": "Wenn es nur eine Reihe von Steinen gibt, oder wenn die unterste Reihe von Steinen die gesamte Breite des Spiels abdeckt, dann bewirkt dieser Vorteil nichts. Andernfalls wird die Combo zurückgesetzt, wenn diese unterste Reihe zerstört wird, während alles andere die Combo um die Anzahl der Steine in dieser untersten Reihe erhöht.\n\nDie unterste Reihe wird in rot hervorgehoben.",
|
||||
|
@ -261,7 +381,7 @@
|
|||
"upgrades.respawn.tooltip": "{{percent}}% der Steine spawnen nach {{delay}}s erneut.",
|
||||
"upgrades.respawn.verbose_description": "Einige Partikeleffekte lassen Sie wissen, wo Ziegelsteine erscheinen werden.",
|
||||
"upgrades.right_is_lava.name": "Vermeiden Sie die rechte Seite",
|
||||
"upgrades.right_is_lava.tooltip": "+{{lvl}} Kombo pro Stein. Combo wird zurückgesetzt, wenn der Ball die linke Seite des Bildschirms trifft.",
|
||||
"upgrades.right_is_lava.tooltip": "+{{lvl}} Kombo pro Stein. Combo wird zurückgesetzt, wenn der Ball die rechte Seite des Bildschirms trifft.",
|
||||
"upgrades.right_is_lava.verbose_description": "Jedes Mal, wenn du einen Ziegelstein zerbrichst, erhöht sich deine Kombo um eins, so dass du von allen weiteren Ziegelsteinen, die du zerbrichst, eine Münze mehr bekommst.\n\nAllerdings wird deine Kombo zurückgesetzt, sobald dein Ball die rechte Seite trifft.\n\nSobald deine Combo ansteigt, wird die rechte Seite rot, um dich daran zu erinnern, dass du es vermeiden solltest, sie zu treffen.\n",
|
||||
"upgrades.sacrifice.help_l1": "Der Verlust eines Lebens löscht alle Steine",
|
||||
"upgrades.sacrifice.help_over": "Der Verlust eines Lebens {{lvl}}x die Combo löscht dann alle Steine",
|
||||
|
@ -270,7 +390,7 @@
|
|||
"upgrades.sapper.help_plural": "Die ersten {{lvl}} Steine, die zerbrochen werden, werden zu Bomben.",
|
||||
"upgrades.sapper.name": "Sapper",
|
||||
"upgrades.sapper.tooltip": "Der erste zerbrochene Ziegelstein wird zu einer Bombe.",
|
||||
"upgrades.sapper.verbose_description": "Statt einfach zu verschwinden, wird der erste Stein, den du zerbrichst, durch einen Bombenstein ersetzt. Wenn du den Ball auf dem Puck abprallen lässt, wird der Effekt wieder aktiviert. Wenn Sie diese Fähigkeit aufwerten, können Sie mehr Bomben platzieren.\n\nDenken Sie daran, dass Bomben die Geschwindigkeit von Münzen in der Nähe beeinflussen, so dass es bei zu vielen Explosionen schwierig werden könnte, die Früchte Ihrer harten Arbeit zu fangen.",
|
||||
"upgrades.sapper.verbose_description": "Anstatt einfach zu verschwinden, wird der erste Stein, den du zerbrichst, durch einen Bombenstein ersetzt. Wenn du den Ball auf dem Paddel abprallen lässt, wird der Effekt wieder aktiviert. Wenn Sie diese Fähigkeit aufwerten, können Sie mehr Bomben platzieren.",
|
||||
"upgrades.shocks.name": "Schocks",
|
||||
"upgrades.shocks.tooltip": "Kollisionen mit explosiven Kugeln",
|
||||
"upgrades.shocks.verbose_description": "Wenn zwei Kugeln zusammenstoßen, tauschen sie ihre Geschwindigkeit aus, lösen eine Explosion aus und gewinnen an Geschwindigkeit, um sie zu trennen.",
|
||||
|
@ -290,47 +410,63 @@
|
|||
"upgrades.slow_down.name": "Langsamer Ball",
|
||||
"upgrades.slow_down.tooltip": "Der Ball bewegt sich langsamer",
|
||||
"upgrades.slow_down.verbose_description": "Der Ball fängt relativ langsam an, aber mit jeder Spielstufe wird er ein bisschen schneller.\n\nEr wird auch schneller, wenn du viel Zeit in einem Level verbringst.\n\nDieser Vorteil macht ihn überschaubarer.\n\nDu kannst ihn jedes Mal beim Start erhalten, indem du den Kindermodus im Menü aktivierst.",
|
||||
"upgrades.smaller_puck.help_plural": "Noch kleinerer Puck und höhere Basis-Kombination",
|
||||
"upgrades.smaller_puck.name": "Kleinerer Puck",
|
||||
"upgrades.smaller_puck.name": "Kleineres Paddel",
|
||||
"upgrades.smaller_puck.tooltip": "Gibt auch +5 Basis-Kombo",
|
||||
"upgrades.smaller_puck.verbose_description": "Dadurch wird der Puck kleiner, was theoretisch einige Eckbälle einfacher macht, aber eigentlich nur den Schwierigkeitsgrad erhöht.\n\nDeshalb gibt es auch einen netten Bonus von +5 Münzen pro Ziegelstein für alle Ziegelsteine, die du nach der Auswahl dieses Pucks kaputt machst.",
|
||||
"upgrades.smaller_puck.verbose_description": "Dadurch wird das Paddel kleiner, was theoretisch einige Eckschüsse einfacher macht, aber eigentlich nur den Schwierigkeitsgrad erhöht.\n\nDeshalb gibt es auch einen netten Bonus von +5 Münzen pro Ziegelstein für alle Ziegelsteine, die du nach der Auswahl dieser Option zerstörst.",
|
||||
"upgrades.soft_reset.name": "Weicher Reset",
|
||||
"upgrades.soft_reset.tooltip": "Combo-Rückstellungen halten {{percent}}%",
|
||||
"upgrades.soft_reset.verbose_description": "Begrenzen Sie die Auswirkungen eines Combo-Resets.",
|
||||
"upgrades.sticky_coins.name": "Klebrige Münzen",
|
||||
"upgrades.sticky_coins.tooltip": "",
|
||||
"upgrades.sticky_coins.verbose_description": "",
|
||||
"upgrades.streak_shots.name": "Glückssträhne",
|
||||
"upgrades.streak_shots.tooltip": "Mehr Münzen, wenn du viele Steine zerbrichst, bevor du auf den Puck springst.",
|
||||
"upgrades.streak_shots.verbose_description": "Jedes Mal, wenn du einen Ziegelstein zerbrichst, erhöht sich deine Kombo (Anzahl der Münzen pro Ziegelstein) um eins.\n\nSobald der Ball jedoch deinen Puck berührt, wird die Kombination auf ihren Standardwert zurückgesetzt und du erhältst nur noch eine Münze pro Stein.\n\nSobald dein Combo den Basiswert übersteigt, wird dein Puck rot, um dich daran zu erinnern, dass deine Combo zerstört wird, wenn du ihn mit dem Ball berührst.",
|
||||
"upgrades.streak_shots.tooltip": "Mehr Münzen, wenn du viele Steine zerbrichst, bevor du auf das Paddel springst.",
|
||||
"upgrades.streak_shots.verbose_description": "Jedes Mal, wenn du einen Stein zerbrichst, erhöht sich dein Combo um eins.\n\nSobald der Ball jedoch Ihr Paddel berührt, wird die Kombination auf ihren Standardwert zurückgesetzt.\n\nSobald deine Kombo den Basiswert übersteigt, wird dein Paddel rot umrandet, um dich daran zu erinnern, dass es deine Kombo zerstört, wenn du es mit dem Ball berührst.",
|
||||
"upgrades.sturdy_bricks.name": "Stabile Ziegel",
|
||||
"upgrades.sturdy_bricks.tooltip": "+{{lvl}} Ziegel HP, +{{percent}}% Münzen, die beim Zerbrechen erzeugt werden",
|
||||
"upgrades.sturdy_bricks.verbose_description": "Jede Stufe dieses Vorteils fügt allen Steinen einen HP hinzu. Du kannst die HP-Zahl mit der Perk \"Hellseher\" sehen. Du kannst den Schaden der Kugeln erhöhen, indem du den \"Piercing\"-Perk bekommst. Jede Stufe des Vorteils erhöht den Spawn von Münzen um 50 %.",
|
||||
"upgrades.superhot.name": "SUPER HEISS",
|
||||
"upgrades.superhot.tooltip": "Die Zeit bewegt sich, wenn sich das Paddel bewegt.",
|
||||
"upgrades.superhot.verbose_description": "SUPERHEISS SUPERHEISS SUPERHEISS SUPERHEISS",
|
||||
"upgrades.telekinesis.help_plural": "Stärkere Wirkung auf den Ball",
|
||||
"upgrades.telekinesis.name": "Telekinese",
|
||||
"upgrades.telekinesis.tooltip": "Der Puck kontrolliert die Flugbahn des Balls",
|
||||
"upgrades.telekinesis.tooltip": "Das Paddel steuert die Flugbahn des Balls",
|
||||
"upgrades.telekinesis.verbose_description": "Du kontrollierst den Ball, während er nach oben fliegt.",
|
||||
"upgrades.three_cushion.name": "Dreiband",
|
||||
"upgrades.three_cushion.tooltip": "+1 Combo pro Treffer an den Seiten und von oben. Die Combo wird zurückgesetzt, wenn Sie einen Ziegel treffen, ohne vorher abzuprallen.",
|
||||
"upgrades.three_cushion.verbose_description": "",
|
||||
"upgrades.top_is_lava.name": "Der Himmel ist die Grenze",
|
||||
"upgrades.top_is_lava.tooltip": "+{{lvl}} Combo pro Stein, wird zurückgesetzt, wenn die Spitze getroffen wird",
|
||||
"upgrades.top_is_lava.verbose_description": "Jedes Mal, wenn du einen Stein zerbrichst, erhöht sich deine Kombo um eins. Allerdings wird deine Kombo zurückgesetzt, sobald dein Ball den oberen Rand des Bildschirms trifft.\n\nWenn deine Kombo über dem Minimum liegt, erscheint oben ein roter Balken, der dich daran erinnert, dass du es vermeiden solltest, ihn zu treffen.",
|
||||
"upgrades.trampoline.name": "Trampolin",
|
||||
"upgrades.trampoline.tooltip": "+{{lvl}} Combo pro Abprall des Pucks,-{{lvl}} Combo pro Abprall an einer beliebigen Grenze",
|
||||
"upgrades.trampoline.tooltip": "+{{lvl}} Combo pro Paddelabprall, -{{lvl}} Combo pro Abprall an einer beliebigen Grenze",
|
||||
"upgrades.trampoline.verbose_description": "Eine der seltenen Combo-Upgrades, die keine Rücksetzbedingung hinzufügen",
|
||||
"upgrades.trickledown.name": "Abfluss",
|
||||
"upgrades.trickledown.tooltip": "Die Münzen erscheinen oben auf dem Bildschirm.",
|
||||
"upgrades.trickledown.verbose_description": "Es könnte Ihnen helfen, ein paar Münzen beiseite zu legen. ",
|
||||
"upgrades.unbounded.help_no_ceiling": "+{{lvl}} Combo pro Stein, keine weiteren Seiten oder Decken",
|
||||
"upgrades.unbounded.name": "Unbegrenzt",
|
||||
"upgrades.unbounded.tooltip": "+{{lvl}} Combo pro Stein, keine Seiten mehr, um den Ball im Spiel zu halten, Gefahr",
|
||||
"upgrades.unbounded.verbose_description": "Ich hoffe, du hast einen Weg gefunden, deinen Ball auf dem Bildschirm zu halten. Es gibt keine Strafen mehr, wenn du die Seiten triffst. Auf Stufe 2+ verschwindet auch die Decke. Dies ist ein fortgeschrittener Vorteil.",
|
||||
"upgrades.transparency.name": "Transparenz",
|
||||
"upgrades.transparency.tooltip": "Je höher der Ball auf dem Bildschirm ist, desto transparenter wird er. Je transparenter sie ist, desto mehr Münzen produziert sie.",
|
||||
"upgrades.transparency.verbose_description": "Je höher die Stufe, desto eher wird der Ball transparent und desto höher ist der Punktebonus.",
|
||||
"upgrades.trickledown.name": "Trickle down economics",
|
||||
"upgrades.trickledown.tooltip": "Die Münzen erscheinen am oberen Rand des Bildschirms.",
|
||||
"upgrades.trickledown.verbose_description": "Es könnte Ihnen helfen, ein paar Münzen zur Seite zu legen.",
|
||||
"upgrades.unbounded.name": "Polsterung",
|
||||
"upgrades.unbounded.tooltip": "Fügt links und rechts des Levels Platz hinzu, aber dein Paddel kann nicht so weit gehen.",
|
||||
"upgrades.unbounded.verbose_description": "Ein weiteres Upgrade könnte Ihnen helfen, die Reichweite Ihres Paddels zu vergrößern.",
|
||||
"upgrades.viscosity.name": "Viskosität",
|
||||
"upgrades.viscosity.tooltip": "Langsamerer Münzfall",
|
||||
"upgrades.viscosity.verbose_description": "Münzen beschleunigen normalerweise durch Schwerkraft und Explosionen auf ziemlich hohe Geschwindigkeiten.\n\nMit dieser Fähigkeit werden sie ständig langsamer, als ob sie sich in einer Art zähflüssiger Flüssigkeit befänden.\n\nDas macht es einfacher, sie zu fangen, und lässt sich gut mit Perks kombinieren, die die Bewegung der Münze beeinflussen.",
|
||||
"upgrades.wind.help_plural": "Stärkere Windkraft",
|
||||
"upgrades.wind.name": "WIND",
|
||||
"upgrades.wind.tooltip": "Puckstellung erzeugt Wind",
|
||||
"upgrades.wind.verbose_description": "Der Wind hängt von der Position des Pucks ab: links weht links, rechts weht rechts. Wirkt sich sowohl auf Bälle als auch auf Münzen aus.",
|
||||
"upgrades.wind.tooltip": "Paddelstellung erzeugt Wind",
|
||||
"upgrades.wind.verbose_description": "Der Wind hängt von der Paddelposition ab: links bläst links, rechts bläst rechts. Wirkt sich sowohl auf Bälle als auch auf Münzen aus.",
|
||||
"upgrades.wrap_left.name": "",
|
||||
"upgrades.wrap_left.tooltip": "",
|
||||
"upgrades.wrap_left.verbose_description": "",
|
||||
"upgrades.wrap_right.name": "",
|
||||
"upgrades.wrap_right.tooltip": "",
|
||||
"upgrades.wrap_right.verbose_description": "",
|
||||
"upgrades.yoyo.name": "Yo-Yo",
|
||||
"upgrades.yoyo.tooltip": "Ball fällt in Richtung Puck",
|
||||
"upgrades.yoyo.tooltip": "Ball fällt in Richtung Paddel",
|
||||
"upgrades.yoyo.verbose_description": "Es ist das Gegenteil von Telekinese, den Ball zu kontrollieren, während er wieder nach unten fällt.",
|
||||
"upgrades.zen.name": "Zen",
|
||||
"upgrades.zen.tooltip": "+{{lvl}} Combo pro Ziegel, wird bei einer Explosion zurückgesetzt",
|
||||
"upgrades.zen.tooltip": "",
|
||||
"upgrades.zen.verbose_description": "Schließlich handelt es sich um ein gewaltfreies Spiel."
|
||||
}
|
||||
|
|
|
@ -3,6 +3,29 @@
|
|||
"confirmRestart.text": "You're about to start a new game. Are you sure you want to continue?",
|
||||
"confirmRestart.title": "Start a new game?",
|
||||
"confirmRestart.yes": "Restart game",
|
||||
"editor.editing.bigger": "Increase level size",
|
||||
"editor.editing.color": "Pick a color in the color list (max 5 per level)",
|
||||
"editor.editing.copy": "Copy level code",
|
||||
"editor.editing.copy_help": "Paste it in the #levels channel in our discord",
|
||||
"editor.editing.credit": "Credits and source",
|
||||
"editor.editing.credit_prompt": "Enter the source url or explanation of your level.",
|
||||
"editor.editing.delete": "Delete level",
|
||||
"editor.editing.down": "Move down all the bricks",
|
||||
"editor.editing.help": "Then click a tile to color it.",
|
||||
"editor.editing.left": "Move all bricks to the left",
|
||||
"editor.editing.play": "Play this level",
|
||||
"editor.editing.rename": "Level name",
|
||||
"editor.editing.rename_prompt": "Please enter a new name for the level",
|
||||
"editor.editing.right": "Move all bricks to the right",
|
||||
"editor.editing.smaller": "Decrease level size",
|
||||
"editor.editing.title": "Editing level : {{name}}",
|
||||
"editor.editing.up": "Move up all the bricks",
|
||||
"editor.help": "Create custom levels and share them for inclusion in the game.",
|
||||
"editor.import": "Import a level",
|
||||
"editor.import_instruction": "Paste a level code to import it in your level list",
|
||||
"editor.locked": "Reach a total score of {{min}} to unlock",
|
||||
"editor.new_level": "New level",
|
||||
"editor.title": "Level Editor",
|
||||
"gameOver.creative": "This run will not be recorded. ",
|
||||
"gameOver.cumulative_total": "Your total cumulative score went from {{startTs}} to {{endTs}}.",
|
||||
"gameOver.lost.summary": "You dropped the ball after catching {{score}} coins.",
|
||||
|
@ -32,12 +55,14 @@
|
|||
"history.columns.score": "Score",
|
||||
"history.columns.started": "Date",
|
||||
"history.help": "See your {{count}} best games.",
|
||||
"history.include_past_versions": "Show past versions too",
|
||||
"history.locked": "Play at least ten games to unlock",
|
||||
"history.title": "Runs history",
|
||||
"lab.help": "Try any build you want",
|
||||
"lab.instructions": "Select upgrades below, then pick a level to play. ",
|
||||
"lab.instructions": "Select upgrades and a level, then click the play button above",
|
||||
"lab.menu_entry": "Creative mode",
|
||||
"lab.reset": "Reset all to 0",
|
||||
"lab.play": "Play",
|
||||
"lab.reset": "Reset",
|
||||
"lab.select_level": "Select a level to play on",
|
||||
"lab.unlocks_at": "Unlocks at total score {{score}}",
|
||||
"level_up.after_buttons": "You just finished level {{level}}/{{max}}.",
|
||||
|
@ -139,6 +164,8 @@
|
|||
"score_panel.title": "{{score}} points at level {{level}}/{{max}} ",
|
||||
"score_panel.upcoming_levels": "Upcoming levels :",
|
||||
"score_panel.upgrades_picked": "Upgrades picked in this game run : ",
|
||||
"settings.autoplay": "Auto play",
|
||||
"settings.autoplay_help": "Start a session with random upgrades and a computer controlled paddle",
|
||||
"settings.basic": "Basic graphics",
|
||||
"settings.basic_help": "Better performance.",
|
||||
"settings.colorful_coins": "Colorful coins",
|
||||
|
@ -163,12 +190,14 @@
|
|||
"settings.load_save_file_help": "Select a save file on your device",
|
||||
"settings.max_coins": " {{max}} coins on screen maximum",
|
||||
"settings.max_coins_help": "Cosmetic only, no effect on score",
|
||||
"settings.max_particles": " {{max}} particles maximum",
|
||||
"settings.max_particles_help": "Limits the number of particles show on screen for visual effect. ",
|
||||
"settings.mobile": "Mobile mode",
|
||||
"settings.mobile_help": "Leaves space under the paddle.",
|
||||
"settings.pointer_lock": "Mouse pointer lock",
|
||||
"settings.pointer_lock_help": "Locks and hides the mouse cursor.",
|
||||
"settings.precise_lighting": "Precise lighting",
|
||||
"settings.precise_lighting_help": "Use a smaller grid for background light effect",
|
||||
"settings.probabilistic_lighting": "Persistence of vision",
|
||||
"settings.probabilistic_lighting_help": "Improve performance when there are more than 150 coins by reusing some of the light of the previous frame",
|
||||
"settings.record": "Record gameplay videos",
|
||||
"settings.record_download": "Download video ({{size}} MB)",
|
||||
"settings.record_help": "Get a video of each level.",
|
||||
|
@ -187,24 +216,30 @@
|
|||
"settings.show_fps_help": "Monitor the app's performance",
|
||||
"settings.show_stats": "Show real time stats",
|
||||
"settings.show_stats_help": "Coins, time, bounces, misses",
|
||||
"settings.smooth_lighting": "Smooth lighting",
|
||||
"settings.smooth_lighting_help": "Blur the background light effects to make them look less square. Increases lag.",
|
||||
"settings.sounds": "Game sounds",
|
||||
"settings.sounds_help": "Can slow down some phones.",
|
||||
"settings.sounds_help": "Beeps, bloops and brrrr",
|
||||
"settings.stress_test": "Stress test",
|
||||
"settings.stress_test_help": "Start a bot controlled game with a very high number of coins, to test the performance limits of your device.",
|
||||
"starting_perks.checked": "When you start a new game, one of those perks will be given to you. Click a perk to exclude it. ",
|
||||
"starting_perks.help": "Choose possible starting upgrades",
|
||||
"starting_perks.random": "All benefits have been removed, the choice will be random.",
|
||||
"starting_perks.title": "Starting perks",
|
||||
"starting_perks.unchecked": "The perks below are not offered as starting perks, but you can click to add them to the pool. ",
|
||||
"unlocks.greyed_out_help": "The grayed out upgrades can be unlocked by increasing your total score. The total score increases every time you score in game.",
|
||||
"unlocks.intro": "Your total score is {{ts}}. Below are all the upgrades and levels the games has to offer. Click an upgrade or level below to start a test game with it.",
|
||||
"unlocks.intro": "Your total score is {{ts}}.Click an upgrade below to start a test game with it.",
|
||||
"unlocks.just_unlocked": "Level unlocked",
|
||||
"unlocks.just_unlocked_plural": "You just unlocked {{count}} levels",
|
||||
"unlocks.level": "<h2>You unlocked {{unlocked}} levels out of {{out_of}}</h2>\n<p>Here are all the game levels, click one to try it out.</p> ",
|
||||
"unlocks.level": "You unlocked {{unlocked}} levels out of {{out_of}}",
|
||||
"unlocks.level_description": "A {{size}}x{{size}} level with {{bricks}} bricks, {{colors}} colors and {{bombs}} bombs.",
|
||||
"unlocks.levels": "Unlocked levels",
|
||||
"unlocks.minScore": "Reach ${{minScore}} in a run to unlock.",
|
||||
"unlocks.minScoreWithPerks": "Reach ${{minScore}} in a run with {{required}} but without {{forbidden}} to unlock.",
|
||||
"unlocks.minTotalScore": "Accumulate a total of ${{score}}",
|
||||
"unlocks.reached": "Your best score was {{reached}}.",
|
||||
"unlocks.title_upgrades": "You unlocked {{unlocked}} upgrades out of {{out_of}}",
|
||||
"unlocks.upgrades": "Unlocked upgrades",
|
||||
"upgrades.addiction.name": "Addiction",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} combo / brick, combo resets {{delay}}s after breaking a brick. ",
|
||||
"upgrades.addiction.verbose_description": "The countdown only starts after breaking the first brick of each level. It stops as soon as all bricks are destroyed.",
|
||||
|
@ -237,6 +272,9 @@
|
|||
"upgrades.bricks_attract_coins.name": "Bricks attract coins",
|
||||
"upgrades.bricks_attract_coins.tooltip": "Helps them stay up there",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "Buoy",
|
||||
"upgrades.buoy.tooltip": "Coins float for {{duration}} seconds on the bottom line. ",
|
||||
"upgrades.buoy.verbose_description": "Effect is most visible in mobile mode",
|
||||
"upgrades.clairvoyant.name": "Clairvoyant",
|
||||
"upgrades.clairvoyant.tooltip": "See upcoming levels, bricks HP and ball direction",
|
||||
"upgrades.clairvoyant.verbose_description": "Helps you pick the right upgrades and understand what's going on with sturdy bricks. Level 2 and 3 bring additional knowledge of dubious utility (reachable in loop mode)",
|
||||
|
@ -253,6 +291,9 @@
|
|||
"upgrades.corner_shot.name": "Corner shot",
|
||||
"upgrades.corner_shot.tooltip": "Lets your paddle overlap with the borders of the screen",
|
||||
"upgrades.corner_shot.verbose_description": "Helps with aiming in the corners. Further levels let you go further out. ",
|
||||
"upgrades.double_or_nothing.name": "Double or nothing",
|
||||
"upgrades.double_or_nothing.tooltip": "Combo climbs {{multiplier}} times faster, but you'll loose {{percent}}% of your score at each reset.",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "Coins, in Space",
|
||||
"upgrades.etherealcoins.tooltip": "Coins are no longer affected by gravity",
|
||||
"upgrades.etherealcoins.verbose_description": "The coins will maintain their speed even after several bounces, and will no longer be affected by gravity.",
|
||||
|
@ -268,10 +309,13 @@
|
|||
"upgrades.forgiving.verbose_description": "The first miss per level is free, then 10% of the combo, then 20% .. ",
|
||||
"upgrades.fountain_toss.name": "Fountain toss",
|
||||
"upgrades.fountain_toss.tooltip": "Gain some combo when you miss some coins. ",
|
||||
"upgrades.fountain_toss.verbose_description": "When you miss a coin and your combo was under {{max}}, your combo has a probability of {{lvl}}/combo to grow by one.",
|
||||
"upgrades.fountain_toss.verbose_description": "When you miss a coin and your combo was under level*30, your combo has a probability of level/combo to grow by one.",
|
||||
"upgrades.ghost_coins.name": "Ghost coins",
|
||||
"upgrades.ghost_coins.tooltip": "Coins slowly pass through bricks",
|
||||
"upgrades.ghost_coins.verbose_description": "It's not a bug, it's a feature ! Coins fly through bricks slowly. Higher levels let them move faster. ",
|
||||
"upgrades.happy_family.name": "Happy family",
|
||||
"upgrades.happy_family.tooltip": "+1 combo per extra ball for each paddle bounce. Combo resets when a ball is lost. ",
|
||||
"upgrades.happy_family.verbose_description": "Only the ball above 1 give combo.",
|
||||
"upgrades.helium.name": "Helium",
|
||||
"upgrades.helium.tooltip": "Gravity reversed left and right of paddle",
|
||||
"upgrades.helium.verbose_description": "This affects the coins and will let the float up until you are ready to pick them up.",
|
||||
|
@ -308,8 +352,11 @@
|
|||
"upgrades.one_more_choice.name": "Extra choice",
|
||||
"upgrades.one_more_choice.tooltip": "Further level ups will offer {{lvl}} more option(s) in the list",
|
||||
"upgrades.one_more_choice.verbose_description": "Every upgrade menu will have one more option. Doesn't increase the number of upgrades you can pick.",
|
||||
"upgrades.ottawa_treaty.name": "Ottawa treaty",
|
||||
"upgrades.ottawa_treaty.tooltip": "Breaking a brick near a bomb disarms it",
|
||||
"upgrades.ottawa_treaty.verbose_description": "The nearby bomb will be replaced by a colored block. If you have sapper, the ball will loose its sapper effect until next bounce. Only one bomb can be replaced at a time.",
|
||||
"upgrades.passive_income.name": "Passive income",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} combo / brick, unless the paddle moved in the last {{time}}s, then it resets instead",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} combo / brick, paddle is immaterial {{time}}s after moving",
|
||||
"upgrades.passive_income.verbose_description": "Some perks can help the balls do what you want without needing to do anything.",
|
||||
"upgrades.picky_eater.name": "Picky eater",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} combo per brick broken, resets on ball color change",
|
||||
|
@ -363,13 +410,15 @@
|
|||
"upgrades.slow_down.name": "Slower ball",
|
||||
"upgrades.slow_down.tooltip": "Ball moves more slowly",
|
||||
"upgrades.slow_down.verbose_description": "The ball starts relatively slow, but every level of your game it will start a bit faster. \n\nIt will also accelerate if you spend a lot of time in one level. \n\nThis perk makes it more manageable. \n\nYou can get it at the start every time by enabling kid mode in the menu.",
|
||||
"upgrades.smaller_puck.help_plural": "Even smaller paddle and higher base combo",
|
||||
"upgrades.smaller_puck.name": "Smaller paddle",
|
||||
"upgrades.smaller_puck.tooltip": "Also gives +5 base combo",
|
||||
"upgrades.smaller_puck.verbose_description": "This makes the paddle smaller, which in theory makes some corner shots easier, but really just raises the difficulty.\n\nThat's why you also get a nice bonus of +5 coins per brick for all bricks you'll break after picking this. ",
|
||||
"upgrades.smaller_puck.tooltip": "Also gives +{{percent}}% coins",
|
||||
"upgrades.smaller_puck.verbose_description": "This makes the paddle smaller, which in theory makes some corner shots easier, but really just raises the difficulty.\n\nThat's why you also get a nice bonus of +50% coins spawn.",
|
||||
"upgrades.soft_reset.name": "Soft reset",
|
||||
"upgrades.soft_reset.tooltip": "Combo resets keeps {{percent}}%",
|
||||
"upgrades.soft_reset.verbose_description": "Limit the impact of a combo reset.",
|
||||
"upgrades.sticky_coins.name": "Sticky coins",
|
||||
"upgrades.sticky_coins.tooltip": "Coins stick to bricks of the same color",
|
||||
"upgrades.sticky_coins.verbose_description": "At level 2, they stick to bricks of any color",
|
||||
"upgrades.streak_shots.name": "Hit streak",
|
||||
"upgrades.streak_shots.tooltip": "More coins if you break many bricks before bouncing on the paddle.",
|
||||
"upgrades.streak_shots.verbose_description": "Every time you break a brick, your combo increases by one. \n\nHowever, as soon as the ball touches your paddle, the combo is reset to its default value.\n\nOnce your combo rises above the base value, your paddle will have a red border to remind you that it will destroy your combo to touch it with the ball.",
|
||||
|
@ -383,6 +432,9 @@
|
|||
"upgrades.telekinesis.name": "Telekinesis",
|
||||
"upgrades.telekinesis.tooltip": "Paddle controls the ball's trajectory",
|
||||
"upgrades.telekinesis.verbose_description": "You control the ball while it's going up. ",
|
||||
"upgrades.three_cushion.name": "Three cushion",
|
||||
"upgrades.three_cushion.tooltip": "+1 combo per hit on sides and top, up to +{{max}} per paddle bounce. Combo resets when you hit a brick without bouncing first. ",
|
||||
"upgrades.three_cushion.verbose_description": "Every hit on a side will raise the combo by one, up to +3. After that, no combo will be gained until next paddle bounce. ",
|
||||
"upgrades.top_is_lava.name": "Sky is the limit",
|
||||
"upgrades.top_is_lava.tooltip": "+{{lvl}} combo per brick, reset when the top is hit",
|
||||
"upgrades.top_is_lava.verbose_description": "Whenever you break a brick, your combo will increase by one. However, your combo will reset as soon as your ball hit the top of the screen. \n\nWhen your combo is above the minimum, a red bar will appear at the top to remind you that you should avoid hitting it. ",
|
||||
|
@ -390,7 +442,7 @@
|
|||
"upgrades.trampoline.tooltip": "+{{lvl}} combo per paddle bounce,-{{lvl}} combo per bounce on any border",
|
||||
"upgrades.trampoline.verbose_description": "One of the rare combo upgrades that don't add a reset condition",
|
||||
"upgrades.transparency.name": "Transparency",
|
||||
"upgrades.transparency.tooltip": "The higher the ball is on the screen, the more transparent it becomes. The more transparent it is, the more coins it produces.",
|
||||
"upgrades.transparency.tooltip": "Ball becomes transparent at the top of the screen. +{{percent}} % coins when all balls are at full transparency",
|
||||
"upgrades.transparency.verbose_description": "Higher levels make the ball transparent sooner and increase the point bonus.",
|
||||
"upgrades.trickledown.name": "Trickle down economics",
|
||||
"upgrades.trickledown.tooltip": "The coins appear at the top of the screen.",
|
||||
|
@ -405,10 +457,16 @@
|
|||
"upgrades.wind.name": "Wind",
|
||||
"upgrades.wind.tooltip": "Paddle position creates wind",
|
||||
"upgrades.wind.verbose_description": "Wind depends on paddle position: left blows left, right blows right. Affects both balls and coins.",
|
||||
"upgrades.wrap_left.name": "Wrap left",
|
||||
"upgrades.wrap_left.tooltip": "Hitting the left side teleports the ball to the right side",
|
||||
"upgrades.wrap_left.verbose_description": "Higher levels might teleport coins too",
|
||||
"upgrades.wrap_right.name": "Wrap right",
|
||||
"upgrades.wrap_right.tooltip": "Hitting the right side teleports the ball to the left side",
|
||||
"upgrades.wrap_right.verbose_description": "Higher levels might teleport coins too",
|
||||
"upgrades.yoyo.name": "Yo-yo",
|
||||
"upgrades.yoyo.tooltip": "Ball falls toward paddle",
|
||||
"upgrades.yoyo.verbose_description": "It's the opposite of telekinesis, control the ball while it's falling back down.",
|
||||
"upgrades.zen.name": "Zen",
|
||||
"upgrades.zen.tooltip": "+{{lvl}} combo per bricks, reset when there's an explosion",
|
||||
"upgrades.zen.verbose_description": "After all, this is a non-violent game. "
|
||||
"upgrades.zen.tooltip": "+{{lvl}} combo every 3s, reset when there's an explosion",
|
||||
"upgrades.zen.verbose_description": ""
|
||||
}
|
||||
|
|
|
@ -3,6 +3,29 @@
|
|||
"confirmRestart.text": "Estás a punto de empezar un nuevo partido: ¿es esto realmente lo que querías?",
|
||||
"confirmRestart.title": "¿Empezar una nueva partida?",
|
||||
"confirmRestart.yes": "Empezar una nueva partida",
|
||||
"editor.editing.bigger": "Aumentar el tamaño del nivel",
|
||||
"editor.editing.color": "Elige un color de la lista de colores (máximo 5 por nivel)",
|
||||
"editor.editing.copy": "Copiar código de nivel",
|
||||
"editor.editing.copy_help": "Pégalo en el canal #levels en nuestro discord",
|
||||
"editor.editing.credit": "Créditos y fuente",
|
||||
"editor.editing.credit_prompt": "Introduce la URL de origen o la explicación de tu nivel.",
|
||||
"editor.editing.delete": "Eliminar nivel",
|
||||
"editor.editing.down": "Baja todos los ladrillos",
|
||||
"editor.editing.help": "Luego haz clic en un mosaico para colorearlo.",
|
||||
"editor.editing.left": "Mueve todos los ladrillos hacia la izquierda",
|
||||
"editor.editing.play": "Juega este nivel",
|
||||
"editor.editing.rename": "Nombre del nivel",
|
||||
"editor.editing.rename_prompt": "Por favor, introduzca un nuevo nombre para el nivel",
|
||||
"editor.editing.right": "Mueve todos los ladrillos hacia la derecha",
|
||||
"editor.editing.smaller": "Disminuir el tamaño del nivel",
|
||||
"editor.editing.title": "Nivel de edición: {{name}}",
|
||||
"editor.editing.up": "Mueve todos los ladrillos hacia arriba",
|
||||
"editor.help": "Crea niveles personalizados y compártelos para incluirlos en el juego.",
|
||||
"editor.import": "Importar un nivel",
|
||||
"editor.import_instruction": "Pegue un código de nivel para importarlo en su lista de niveles",
|
||||
"editor.locked": "Alcanza una puntuación total de {{min}} para desbloquear",
|
||||
"editor.new_level": "Nuevo nivel",
|
||||
"editor.title": "Editor de niveles",
|
||||
"gameOver.creative": "Esta parte de la prueba no se grabará.",
|
||||
"gameOver.cumulative_total": "Su puntuación total acumulada ha pasado de {{startTs}} a {{endTs}}.",
|
||||
"gameOver.lost.summary": "Se te ha caído la bola después de coger {{score}} monedas.",
|
||||
|
@ -32,12 +55,14 @@
|
|||
"history.columns.score": "Puntuación",
|
||||
"history.columns.started": "Fecha",
|
||||
"history.help": "Enumera tus {{count}} mejores juegos.",
|
||||
"history.include_past_versions": "",
|
||||
"history.locked": "Juega primero al menos diez partidos",
|
||||
"history.title": "Historia",
|
||||
"lab.help": "Prueba cualquier combinación de mejoras y niveles.",
|
||||
"lab.instructions": "Selecciona las mejoras que aparecen a continuación y elige el nivel al que quieres jugar. .",
|
||||
"lab.instructions": "Selecciona mejoras y un nivel, luego haz clic en el botón de reproducción de arriba.",
|
||||
"lab.menu_entry": "Modo creativo",
|
||||
"lab.reset": "Eliminar todas las mejoras",
|
||||
"lab.play": "Jugar",
|
||||
"lab.reset": "Reiniciar",
|
||||
"lab.select_level": "Selecciona un nivel para jugar",
|
||||
"lab.unlocks_at": "Desbloqueado a partir de una puntuación total de {{score}}.",
|
||||
"level_up.after_buttons": "Acabas de completar el nivel {{level}}/{{max}}.",
|
||||
|
@ -139,6 +164,8 @@
|
|||
"score_panel.title": "{{score}} puntos en {{level}}/{{max}} nivel",
|
||||
"score_panel.upcoming_levels": "Niveles de partido :",
|
||||
"score_panel.upgrades_picked": "Mejoras elegidas durante el juego :",
|
||||
"settings.autoplay": "Auto-reproducción",
|
||||
"settings.autoplay_help": "Comienza una sesión con mejoras aleatorias y una paleta controlada por computadora.",
|
||||
"settings.basic": "Gráficos básicos",
|
||||
"settings.basic_help": "Mejor rendimiento.",
|
||||
"settings.colorful_coins": "Monedas de colores",
|
||||
|
@ -163,12 +190,14 @@
|
|||
"settings.load_save_file_help": "Seleccione un archivo guardado en su dispositivo",
|
||||
"settings.max_coins": " {{max}} monedas en pantalla máximo",
|
||||
"settings.max_coins_help": "Solo cosmético, sin efecto en la puntuación.",
|
||||
"settings.max_particles": " {{max}} partículas máximo",
|
||||
"settings.max_particles_help": "Limita la cantidad de partículas que se muestran en la pantalla para lograr un efecto visual.",
|
||||
"settings.mobile": "Modo móvil",
|
||||
"settings.mobile_help": "Deja espacio debajo de la paleta.",
|
||||
"settings.pointer_lock": "Bloqueo del puntero del ratón",
|
||||
"settings.pointer_lock_help": "Bloquea y oculta el cursor del mouse.",
|
||||
"settings.precise_lighting": "Iluminación precisa",
|
||||
"settings.precise_lighting_help": "Utilice una cuadrícula más pequeña para el efecto de luz de fondo.",
|
||||
"settings.probabilistic_lighting": "Persistencia de la visión",
|
||||
"settings.probabilistic_lighting_help": "Mejora el rendimiento cuando hay más de 150 monedas reutilizando parte de la luz del cuadro anterior",
|
||||
"settings.record": "Grabar vídeos de juego",
|
||||
"settings.record_download": "Descargar vídeo ({{size}} MB)",
|
||||
"settings.record_help": "Obtenga un vídeo de cada nivel.",
|
||||
|
@ -187,24 +216,30 @@
|
|||
"settings.show_fps_help": "Supervisar el rendimiento de la aplicación",
|
||||
"settings.show_stats": "Mostrar estadísticas en tiempo real",
|
||||
"settings.show_stats_help": "Monedas, tiempo, rebotes, fallos.",
|
||||
"settings.smooth_lighting": "Iluminación suave",
|
||||
"settings.smooth_lighting_help": "Desenfoca los efectos de luz de fondo para que se vean menos cuadrados. Aumenta el retardo.",
|
||||
"settings.sounds": "Sonidos del juego",
|
||||
"settings.sounds_help": "Puede ralentizar algunos teléfonos.",
|
||||
"settings.sounds_help": "Pitidos, bloops y brrrr",
|
||||
"settings.stress_test": "Prueba de estrés",
|
||||
"settings.stress_test_help": "Inicie un juego controlado por bot con una cantidad muy alta de monedas para probar los límites de rendimiento de su dispositivo.",
|
||||
"starting_perks.checked": "Al empezar una partida nueva, recibirás una de esas ventajas. Haz clic en una ventaja para excluirla.",
|
||||
"starting_perks.help": "Elija posibles actualizaciones iniciales",
|
||||
"starting_perks.random": "Se han eliminado todos los beneficios, la elección será aleatoria.",
|
||||
"starting_perks.title": "Beneficios iniciales",
|
||||
"starting_perks.unchecked": "Los beneficios a continuación no se ofrecen como beneficios iniciales, pero puedes hacer clic para agregarlos al grupo.",
|
||||
"unlocks.greyed_out_help": "Los objetos en gris pueden desbloquearse aumentando tu puntuación total. La puntuación total aumenta cada vez que consigues puntos en el juego.",
|
||||
"unlocks.intro": "Tu puntuación total es {{ts}}. A continuación encontrarás todas las mejoras y niveles que ofrece el juego. Haz clic en uno de ellos para probarlo en una partida de prueba.",
|
||||
"unlocks.intro": "",
|
||||
"unlocks.just_unlocked": "Nivel desbloqueado",
|
||||
"unlocks.just_unlocked_plural": "Acabas de desbloquear {{count}} niveles",
|
||||
"unlocks.level": "<h2>Has desbloqueado {{unlocked}} niveles en {{out_of}}</h2>\n<p>Aquí están todos los niveles del juego, haz clic en uno para probarlo. </p> ",
|
||||
"unlocks.level": "",
|
||||
"unlocks.level_description": "Un nivel {{size}}x{{size}} con {{bricks}} ladrillos, {{colors}} colores y {{bombs}} bombas.",
|
||||
"unlocks.levels": "",
|
||||
"unlocks.minScore": "Alcanza una puntuación de ${{minScore}} en una partida para desbloquearla.",
|
||||
"unlocks.minScoreWithPerks": "Alcanzar ${{minScore}} en un juego con {{required}} pero sin {{forbidden}}.",
|
||||
"unlocks.minTotalScore": "Acumula un total de ${{score}}",
|
||||
"unlocks.reached": "Tu mejor puntuación hasta ahora es {{reached}}.",
|
||||
"unlocks.title_upgrades": "Has desbloqueado {{unlocked}} mejoras en {{out_of}}.",
|
||||
"unlocks.upgrades": "",
|
||||
"upgrades.addiction.name": "Adicción",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} combo / ladrillo, combo perdido después de {{delay}}s sin romper ningún ladrillo",
|
||||
"upgrades.addiction.verbose_description": "La cuenta atrás sólo comienza una vez que se ha destruido el primer ladrillo del nivel, y se detiene en cuanto no hay más ladrillos.",
|
||||
|
@ -237,6 +272,9 @@
|
|||
"upgrades.bricks_attract_coins.name": "Los ladrillos atraen monedas",
|
||||
"upgrades.bricks_attract_coins.tooltip": "Les ayuda a permanecer allí arriba.",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "Boya",
|
||||
"upgrades.buoy.tooltip": "Las monedas flotan durante {{duration}} segundos en la línea inferior.",
|
||||
"upgrades.buoy.verbose_description": "El efecto es más visible en el modo móvil.",
|
||||
"upgrades.clairvoyant.name": "Perspicaz",
|
||||
"upgrades.clairvoyant.tooltip": "Revela los niveles, el PV de los ladrillos y la dirección de las balas",
|
||||
"upgrades.clairvoyant.verbose_description": "Te ayuda a elegir las mejoras adecuadas y a entender qué ocurre con los \"ladrillos macizos\". Los niveles 2 y 3 (en modo bucle) proporcionan información adicional de dudosa utilidad.",
|
||||
|
@ -253,6 +291,9 @@
|
|||
"upgrades.corner_shot.name": "Tiro de esquina",
|
||||
"upgrades.corner_shot.tooltip": "Deja que tu raqueta salga del área enmarcada",
|
||||
"upgrades.corner_shot.verbose_description": "Te ayuda a apuntar a las esquinas",
|
||||
"upgrades.double_or_nothing.name": "",
|
||||
"upgrades.double_or_nothing.tooltip": "",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "Moneda espacial",
|
||||
"upgrades.etherealcoins.tooltip": "Las piezas ya no se ven afectadas por la gravedad",
|
||||
"upgrades.etherealcoins.verbose_description": "Las monedas mantendrán su velocidad incluso después de varios rebotes y ya no se verán afectadas por la gravedad.",
|
||||
|
@ -268,10 +309,13 @@
|
|||
"upgrades.forgiving.verbose_description": " El primer ladrillo perdido por nivel no cuesta nada, el siguiente 10%, 20% y así sucesivamente.",
|
||||
"upgrades.fountain_toss.name": "Moneda en la fuente",
|
||||
"upgrades.fountain_toss.tooltip": "A veces ganas un pequeño combo cuando pierdes monedas.",
|
||||
"upgrades.fountain_toss.verbose_description": "Cuando se pierde una moneda mientras tu combo estaba por debajo de {{max}}, tu combo tiene una probabilidad de {{lvl}}/combo de incrementarse.",
|
||||
"upgrades.fountain_toss.verbose_description": "Cuando pierdes una moneda y tu combo está por debajo del nivel*30, tu combo tiene una probabilidad de nivel/combo de crecer en uno.",
|
||||
"upgrades.ghost_coins.name": "Habitaciones fantasma",
|
||||
"upgrades.ghost_coins.tooltip": "Las monedas atraviesan los ladrillos lentamente",
|
||||
"upgrades.ghost_coins.verbose_description": "No es un error, ¡es una característica! Las piezas atraviesan los ladrillos lentamente. Los niveles más altos permiten que las monedas pasen más rápido a través de los ladrillos.",
|
||||
"upgrades.happy_family.name": "",
|
||||
"upgrades.happy_family.tooltip": "",
|
||||
"upgrades.happy_family.verbose_description": "",
|
||||
"upgrades.helium.name": "Helio",
|
||||
"upgrades.helium.tooltip": "Las piezas flotan en lugar de caer alrededor de la raqueta.",
|
||||
"upgrades.helium.verbose_description": "Las monedas esperarán a estar debajo de la raqueta para caer.",
|
||||
|
@ -308,8 +352,11 @@
|
|||
"upgrades.one_more_choice.name": "La respuesta D",
|
||||
"upgrades.one_more_choice.tooltip": "1 opción de mejora adicional disponible hasta el final del juego",
|
||||
"upgrades.one_more_choice.verbose_description": "Cada menú de mejoras tendrá una opción adicional. Esto no aumenta el número de mejoras que puede elegir, pero le ayuda a crear el perfil ideal. \"Respuesta D\" es una referencia a un sketch clásico.",
|
||||
"upgrades.ottawa_treaty.name": "Tratado de Ottawa",
|
||||
"upgrades.ottawa_treaty.tooltip": "Romper un ladrillo cerca de una bomba la desarma.",
|
||||
"upgrades.ottawa_treaty.verbose_description": "La bomba cercana será reemplazada por un bloque de color. Si tienes zapador, la pelota perderá su efecto hasta el próximo rebote. Solo se puede reemplazar una bomba a la vez.",
|
||||
"upgrades.passive_income.name": "Ingresos pasivos",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} combo / ladrillo, a menos que la raqueta se haya movido en los últimos {{time}} segundos, en cuyo caso se pierde el combo.",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} combo/bloque, la paleta es inmaterial {{time}}s después de mover",
|
||||
"upgrades.passive_income.verbose_description": "Algunas mejoras hacen que las pelotas se muevan sin necesidad de poner la raqueta en movimiento.",
|
||||
"upgrades.picky_eater.name": "Comer por colores",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} combo por ladrillo roto del color de la bola, combo perdido en caso contrario",
|
||||
|
@ -363,13 +410,15 @@
|
|||
"upgrades.slow_down.name": "Bola lenta",
|
||||
"upgrades.slow_down.tooltip": "El balón se mueve más despacio",
|
||||
"upgrades.slow_down.verbose_description": "La bola empieza relativamente despacio, pero con cada nivel del juego empieza un poco más rápido, y también se acelera si pasas mucho tiempo en un nivel.\n\nEsta ventaja hace que la bola sea más fácil de manejar.\n\nPuedes conseguirla al principio de cada partida activando el modo niño en el menú.",
|
||||
"upgrades.smaller_puck.help_plural": "La raqueta se encoge aún más y el combo vuelve a aumentar.",
|
||||
"upgrades.smaller_puck.name": "Raqueta más pequeña",
|
||||
"upgrades.smaller_puck.tooltip": "También da +5 combo",
|
||||
"upgrades.smaller_puck.verbose_description": "Recibes una bonificación de combo permanente de +5 por elegir esta mejora.",
|
||||
"upgrades.smaller_puck.tooltip": "También otorga +{{percent}}% monedas",
|
||||
"upgrades.smaller_puck.verbose_description": "Esto hace que la paleta sea más pequeña, lo que en teoría facilita algunos tiros de esquina, pero en realidad solo aumenta la dificultad.\n\nPor eso también obtienes una buena bonificación de +50% en la generación de monedas.",
|
||||
"upgrades.soft_reset.name": "Restablecimiento progresivo",
|
||||
"upgrades.soft_reset.tooltip": "Al reiniciar el combo se conserva el {{percent}}% de los puntos",
|
||||
"upgrades.soft_reset.verbose_description": "Limita el impacto de un reinicio de combo.",
|
||||
"upgrades.sticky_coins.name": "Monedas pegajosas",
|
||||
"upgrades.sticky_coins.tooltip": "",
|
||||
"upgrades.sticky_coins.verbose_description": "",
|
||||
"upgrades.streak_shots.name": "Secuencia de destrucción",
|
||||
"upgrades.streak_shots.tooltip": "Más piezas si rompes varios ladrillos a la vez.",
|
||||
"upgrades.streak_shots.verbose_description": "Cada vez que rompes un ladrillo, tu combo aumenta. El combo se pone a cero cuando la pelota golpea la raqueta. Una vez que tu combo supera el valor base, tu raqueta se vuelve roja para recordarte que tocarla con la pelota destruirá tu combo.",
|
||||
|
@ -383,6 +432,9 @@
|
|||
"upgrades.telekinesis.name": "Telequinesis",
|
||||
"upgrades.telekinesis.tooltip": "Control de la trayectoria del balón",
|
||||
"upgrades.telekinesis.verbose_description": "Controla la bola mientras sube.",
|
||||
"upgrades.three_cushion.name": "Tres cojines",
|
||||
"upgrades.three_cushion.tooltip": "+1 de combo por golpe en los laterales y la parte superior, hasta +{{max}} por cada rebote de la paleta. El combo se reinicia al golpear un ladrillo sin rebotar primero.",
|
||||
"upgrades.three_cushion.verbose_description": "Cada golpe lateral aumentará el combo en uno, hasta +3. Después, no se obtendrá ningún combo hasta el siguiente rebote de la paleta.",
|
||||
"upgrades.top_is_lava.name": "Icare",
|
||||
"upgrades.top_is_lava.tooltip": "+{{lvl}} combo por ladrillo, perdido en el rebote del techo",
|
||||
"upgrades.top_is_lava.verbose_description": "Cada vez que rompas un ladrillo, tu combo aumentará en uno. Sin embargo, tu combo se reiniciará en cuanto tu bola llegue a la parte superior de la pantalla.\n\nCuando tu combo supere el mínimo, aparecerá una barra roja en la parte superior de la pantalla para recordarte que debes evitar golpearla.",
|
||||
|
@ -390,12 +442,12 @@
|
|||
"upgrades.trampoline.tooltip": "+{{lvl}} combo cada vez que una pelota rebota en la raqueta,-{{lvl}} combo cada vez que una pelota rebota en uno de los bordes",
|
||||
"upgrades.trampoline.verbose_description": "Una de las pocas mejoras que no tiene una condición de reinicio",
|
||||
"upgrades.transparency.name": "Transparencia",
|
||||
"upgrades.transparency.tooltip": "Cuanto más alta esté la bola en la pantalla, más transparente se volverá. Cuanto más transparente sea, más monedas producirá.",
|
||||
"upgrades.transparency.tooltip": "La bola se vuelve transparente en la parte superior de la pantalla. +{{percent}} % monedas cuando todas las bolas son completamente transparentes",
|
||||
"upgrades.transparency.verbose_description": "Los niveles más altos hacen que la pelota se vuelva transparente más rápidamente y aumentan la bonificación de puntos.",
|
||||
"upgrades.trickledown.name": "Escorrentía",
|
||||
"upgrades.trickledown.tooltip": "Las monedas aparecen en la parte superior de la pantalla.",
|
||||
"upgrades.trickledown.verbose_description": "Podría ayudarte a ahorrar algunas monedas. ",
|
||||
"upgrades.unbounded.name": "Liberado, entregado",
|
||||
"upgrades.unbounded.name": "Espacio libre",
|
||||
"upgrades.unbounded.tooltip": "+{{lvl}} combo por ladrillo, más lados para mantener la pelota en juego, peligro",
|
||||
"upgrades.unbounded.verbose_description": "Espero que hayas encontrado la forma de mantener tu bola en la pantalla. En el nivel 2+, el techo también desaparecerá. Se trata de una ventaja avanzada.",
|
||||
"upgrades.viscosity.name": "Fluido viscoso",
|
||||
|
@ -405,10 +457,16 @@
|
|||
"upgrades.wind.name": "Viva el viento",
|
||||
"upgrades.wind.tooltip": "La posición de la raqueta crea viento",
|
||||
"upgrades.wind.verbose_description": "El viento depende de la posición de la raqueta en la pantalla, hacia la izquierda si está a la izquierda, hacia la derecha si está a la derecha.\nAfecta a pelotas y piezas.",
|
||||
"upgrades.wrap_left.name": "",
|
||||
"upgrades.wrap_left.tooltip": "",
|
||||
"upgrades.wrap_left.verbose_description": "",
|
||||
"upgrades.wrap_right.name": "",
|
||||
"upgrades.wrap_right.tooltip": "",
|
||||
"upgrades.wrap_right.verbose_description": "",
|
||||
"upgrades.yoyo.name": "Yo-Yo",
|
||||
"upgrades.yoyo.tooltip": "La pelota desciende hacia la raqueta.",
|
||||
"upgrades.yoyo.verbose_description": "Es lo contrario de la Telequinesis: controlar la pelota mientras cae hacia la raqueta.",
|
||||
"upgrades.zen.name": "Zen",
|
||||
"upgrades.zen.tooltip": "+{{lvl}} combo por ladrillo, hasta que haya una explosión",
|
||||
"upgrades.zen.verbose_description": "Básicamente es un juego no violento."
|
||||
"upgrades.zen.tooltip": "",
|
||||
"upgrades.zen.verbose_description": ""
|
||||
}
|
||||
|
|
|
@ -3,6 +3,29 @@
|
|||
"confirmRestart.text": "Vous êtes sur le point de commencer une nouvelle partie, est-ce vraiment ce que vous vouliez ?",
|
||||
"confirmRestart.title": "Démarrer une nouvelle partie ?",
|
||||
"confirmRestart.yes": "Commencer une nouvelle partie",
|
||||
"editor.editing.bigger": "Augmenter la taille du niveau",
|
||||
"editor.editing.color": "Choisissez une couleur dans la liste des couleurs (max 5 par niveau)",
|
||||
"editor.editing.copy": "Copier le code du niveau",
|
||||
"editor.editing.copy_help": "Collez-le dans le canal #levels de notre discord",
|
||||
"editor.editing.credit": "Crédits et source",
|
||||
"editor.editing.credit_prompt": "Entrez l'url source ou l'explication de votre niveau.",
|
||||
"editor.editing.delete": "Supprimer le niveau",
|
||||
"editor.editing.down": "Déplacez toutes les briques vers le bas",
|
||||
"editor.editing.help": "Cliquez ensuite sur une tuile pour la colorier.",
|
||||
"editor.editing.left": "Déplacer toutes les briques vers la gauche",
|
||||
"editor.editing.play": "Jouez à ce niveau",
|
||||
"editor.editing.rename": "Nom du niveau",
|
||||
"editor.editing.rename_prompt": "Veuillez saisir un nouveau nom pour le niveau",
|
||||
"editor.editing.right": "Déplacer toutes les briques vers la droite",
|
||||
"editor.editing.smaller": "Diminuer la taille du niveau",
|
||||
"editor.editing.title": "Niveau d'édition : {{name}}",
|
||||
"editor.editing.up": "Déplacez toutes les briques",
|
||||
"editor.help": "Créez des niveaux personnalisés et partagez-les pour les inclure dans le jeu.",
|
||||
"editor.import": "Importer un niveau",
|
||||
"editor.import_instruction": "Collez un code de niveau pour l'importer dans votre liste de niveaux",
|
||||
"editor.locked": "Atteignez un score total de {{min}} pour débloquer",
|
||||
"editor.new_level": "Nouveau niveau",
|
||||
"editor.title": "Éditeur de niveau",
|
||||
"gameOver.creative": "Cette partie de test ne sera pas enregistrée.",
|
||||
"gameOver.cumulative_total": "Votre score total cumulé est passé de {{startTs}} à {{endTs}}.",
|
||||
"gameOver.lost.summary": "Vous avez fait tomber la balle après avoir attrapé {{score}} pièces.",
|
||||
|
@ -32,12 +55,14 @@
|
|||
"history.columns.score": "Score",
|
||||
"history.columns.started": "Date",
|
||||
"history.help": "Liste vos {{count}} meilleurs parties.",
|
||||
"history.include_past_versions": "",
|
||||
"history.locked": "Jouez d'abord au moins dix parties",
|
||||
"history.title": "Historique",
|
||||
"lab.help": "Essayez n'importe quel combinaison d'améliorations et de niveaux.",
|
||||
"lab.instructions": "Sélectionnez les améliorations ci-dessous, puis choisissez le niveau à jouer. .",
|
||||
"lab.instructions": "Sélectionnez les améliorations et un niveau, puis cliquez sur le bouton \"jouer\" ci-dessus",
|
||||
"lab.menu_entry": "Mode créatif",
|
||||
"lab.reset": "Retirer toutes les améliorations",
|
||||
"lab.play": "Jouer",
|
||||
"lab.reset": "Réinitialiser",
|
||||
"lab.select_level": "Sélectionnez un niveau sur lequel jouer",
|
||||
"lab.unlocks_at": "Déverrouillé à partir d'un score total de {{score}}",
|
||||
"level_up.after_buttons": "Vous venez de terminer le niveau {{level}}/{{max}}.",
|
||||
|
@ -139,6 +164,8 @@
|
|||
"score_panel.title": "{{score}} points au niveau {{level}}/{{max}} ",
|
||||
"score_panel.upcoming_levels": "Niveaux de la parties : ",
|
||||
"score_panel.upgrades_picked": "Améliorations choisies pendant la partie :",
|
||||
"settings.autoplay": "Lecture automatique",
|
||||
"settings.autoplay_help": "Démarrez une session avec des mises à niveau aléatoires et une pagaie contrôlée par ordinateur",
|
||||
"settings.basic": "Graphismes simplifiés",
|
||||
"settings.basic_help": "Meilleures performances.",
|
||||
"settings.colorful_coins": "Pièces colorées",
|
||||
|
@ -163,12 +190,14 @@
|
|||
"settings.load_save_file_help": "Depuis un fichier ",
|
||||
"settings.max_coins": "{{max}} pièces affichées maximum",
|
||||
"settings.max_coins_help": "Visuel uniquement, pas d'impact sur le score",
|
||||
"settings.max_particles": " {{max}} particules maximum",
|
||||
"settings.max_particles_help": "Limite le nombre de particules affichées à l'écran pour les effets visuels",
|
||||
"settings.mobile": "Mode mobile",
|
||||
"settings.mobile_help": "Laisse un espace sous la raquette.",
|
||||
"settings.pointer_lock": "Verrouillage du pointeur",
|
||||
"settings.pointer_lock_help": "Cache aussi le curseur de la souris.",
|
||||
"settings.precise_lighting": "Éclairage précis",
|
||||
"settings.precise_lighting_help": "Utilisez une grille plus petite pour l'effet de lumière d'arrière-plan",
|
||||
"settings.probabilistic_lighting": "Persistance de la vision",
|
||||
"settings.probabilistic_lighting_help": "Améliorez les performances lorsqu'il y a plus de 150 pièces en réutilisant une partie de la lumière de l'image précédente",
|
||||
"settings.record": "Enregistrer des vidéos de jeu",
|
||||
"settings.record_download": "Télécharger la vidéo ({{size}} MB)",
|
||||
"settings.record_help": "Obtenez une vidéo de chaque niveau.",
|
||||
|
@ -187,24 +216,30 @@
|
|||
"settings.show_fps_help": "Surveiller la performance du jeu",
|
||||
"settings.show_stats": "Statistiques en temps réel",
|
||||
"settings.show_stats_help": "Pièces, temps, rebonds, ratés",
|
||||
"settings.smooth_lighting": "Éclairage doux",
|
||||
"settings.smooth_lighting_help": "Floutez les effets de lumière d'arrière-plan pour les rendre moins carrés. Augmente le décalage.",
|
||||
"settings.sounds": "Sons du jeu",
|
||||
"settings.sounds_help": "Ralentis certains téléphones.",
|
||||
"settings.sounds_help": "Bips, bloops et brrrr",
|
||||
"settings.stress_test": "Test de stress",
|
||||
"settings.stress_test_help": "Démarrez un jeu contrôlé par un bot avec un nombre très élevé de pièces, pour tester les limites de performances de votre appareil.",
|
||||
"starting_perks.checked": "Lorsque vous démarrez une nouvelle partie, l'un de ces avantages vous sera attribué. Cliquez sur un avantage pour l'exclure.",
|
||||
"starting_perks.help": "Choisissez les avantages de départ",
|
||||
"starting_perks.random": "Tous les avantages ont été retirés, le choix sera aléatoire.",
|
||||
"starting_perks.title": "Avantages de départ",
|
||||
"starting_perks.unchecked": "Les avantages ci-dessous ne sont pas proposés comme avantages de départ, mais vous pouvez cliquer pour les ajouter aux avantages de départ possibles.",
|
||||
"unlocks.greyed_out_help": "Les éléments grisées peuvent être débloquées en augmentant votre score total. Le score total augmente à chaque fois que vous marquez des points dans le jeu.",
|
||||
"unlocks.intro": "Votre score total est de {{ts}}. Vous trouverez ci-dessous toutes les améliorations et tous les niveaux que le jeu peut offrir. Cliquez sur l'un d'entre eux pour les essayer dans une partie de test. ",
|
||||
"unlocks.intro": "",
|
||||
"unlocks.just_unlocked": "Niveau débloqué",
|
||||
"unlocks.just_unlocked_plural": "Vous venez de débloquer {{count}} niveaux",
|
||||
"unlocks.level": "<h2>Vous avez débloqué {{unlocked}} niveaux sur {{out_of}}</h2>\n<p>Voici tous les niveaux du jeu, cliquez sur l'un d'eux pour l'essayer. </p> ",
|
||||
"unlocks.level": "",
|
||||
"unlocks.level_description": "Un niveau {{size}}x{{size}} avec {{bricks}} briques, {{colors}} couleurs et {{bombs}} bombes.",
|
||||
"unlocks.levels": "",
|
||||
"unlocks.minScore": "Atteignez un score de ${{minScore}} dans une partie pour débloquer.",
|
||||
"unlocks.minScoreWithPerks": "Atteignez ${{minScore}} dans une partie avec {{required}} mais sans {{forbidden}}.",
|
||||
"unlocks.minTotalScore": "Accumuler un total de ${{score}}",
|
||||
"unlocks.reached": "Votre meilleur score pour l'instant est {{reached}}.",
|
||||
"unlocks.title_upgrades": "Vous avez débloqué {{unlocked}} améliorations sur {{out_of}}",
|
||||
"unlocks.upgrades": "",
|
||||
"upgrades.addiction.name": "Addiction",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} combo / brique, combo perdu après {{delay}}s sans casser de briques",
|
||||
"upgrades.addiction.verbose_description": "Le décompte ne commence qu'à parti de la destruction de la première brique du niveau, et s'arrête dès qu'il n'y a plus de briques. ",
|
||||
|
@ -237,6 +272,9 @@
|
|||
"upgrades.bricks_attract_coins.name": "Briques attirent les pièces",
|
||||
"upgrades.bricks_attract_coins.tooltip": "Aide à garder les pièces en suspension",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "Bouée",
|
||||
"upgrades.buoy.tooltip": "Les pièces flottent pendant {{duration}} secondes sur la ligne du bas.",
|
||||
"upgrades.buoy.verbose_description": "L'effet est plus visible en mode mobile",
|
||||
"upgrades.clairvoyant.name": "Clairvoyant",
|
||||
"upgrades.clairvoyant.tooltip": "Révèle les niveaux, PV des briques et direction des balles",
|
||||
"upgrades.clairvoyant.verbose_description": "Vous aide à choisir les bonnes améliorations et à comprendre ce qu'il se passe avec \"briques solides\". Les niveaux 2 et 3 (en mode loop) amènent des informations complémentaires d'une utilité douteuse. ",
|
||||
|
@ -253,6 +291,9 @@
|
|||
"upgrades.corner_shot.name": "Tir en coin",
|
||||
"upgrades.corner_shot.tooltip": "Laisse votre raquette sortir de la zone encadrée",
|
||||
"upgrades.corner_shot.verbose_description": "Aide à viser dans les coins",
|
||||
"upgrades.double_or_nothing.name": "",
|
||||
"upgrades.double_or_nothing.tooltip": "",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "Monnaie spatiale ",
|
||||
"upgrades.etherealcoins.tooltip": "Les pièces ne subissent plus la gravité ou la friction",
|
||||
"upgrades.etherealcoins.verbose_description": "Les pièces garderont leur vitesse même après plusieurs rebonds, et ne subirons plus la gravité. ",
|
||||
|
@ -268,10 +309,13 @@
|
|||
"upgrades.forgiving.verbose_description": " La première brique ratée par niveau ne coûte rien, la suivante 10%, 20%, etc.",
|
||||
"upgrades.fountain_toss.name": "Pièce dans la fontaine",
|
||||
"upgrades.fountain_toss.tooltip": "Gagnez parfois un peu de combo quand vous perdez des pièces.",
|
||||
"upgrades.fountain_toss.verbose_description": "Quand une pièce est perdue alors que votre combo était en dessous de {{max}}, votre combo à une probabilité de {{lvl}}/combo d'être incrémenté",
|
||||
"upgrades.fountain_toss.verbose_description": "Lorsque vous manquez une pièce et que votre combo était inférieur au niveau*30, votre combo a une probabilité de niveau/combo d'augmenter d'un.",
|
||||
"upgrades.ghost_coins.name": "Pièces fantôme",
|
||||
"upgrades.ghost_coins.tooltip": "Les pièces traversent les briques doucement",
|
||||
"upgrades.ghost_coins.verbose_description": "Ce n'est pas une bug, c'est une fonctionnalité ! Les pièces passent à travers les briques doucement. Les niveaux plus élevés permettent aux pièce de traverser les briques plus vite.",
|
||||
"upgrades.happy_family.name": "",
|
||||
"upgrades.happy_family.tooltip": "",
|
||||
"upgrades.happy_family.verbose_description": "",
|
||||
"upgrades.helium.name": "Hélium",
|
||||
"upgrades.helium.tooltip": "Les pièce flottent au lieu de tomber autours de la raquette.",
|
||||
"upgrades.helium.verbose_description": "Les pièces attendront d'être sous la raquette pour tomber. ",
|
||||
|
@ -308,8 +352,11 @@
|
|||
"upgrades.one_more_choice.name": "La réponse D",
|
||||
"upgrades.one_more_choice.tooltip": "1 choix supplémentaire d'amélioration proposé jusqu'à la fin de la partie",
|
||||
"upgrades.one_more_choice.verbose_description": "Chaque menu d'amélioration comportera une option supplémentaire. Cela n'augmente pas le nombre d'améliorations que vous pouvez choisir, mais vous aide à créer le profile idéal. \"La réponse D\" est une référence à un sketch classique. ",
|
||||
"upgrades.ottawa_treaty.name": "Traité d'Ottawa",
|
||||
"upgrades.ottawa_treaty.tooltip": "Casser une brique près d'une bombe la désamorce",
|
||||
"upgrades.ottawa_treaty.verbose_description": "La bombe à proximité sera remplacée par un bloc coloré. Si vous possédez un sapeur, la balle perdra son effet sapeur jusqu'au prochain rebond. Une seule bombe peut être remplacée à la fois.",
|
||||
"upgrades.passive_income.name": "Revenu passif",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} combo / brique, sauf si la raquette à bougé dans les {{time}} dernières secondes, combo perdu dans ce cas",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} combo / brique, la raquette est immatérielle {{time}}s après le déplacement",
|
||||
"upgrades.passive_income.verbose_description": "Certaines amélioration font bouger les balles sans avoir besoin de mettre la raquette en mouvement.",
|
||||
"upgrades.picky_eater.name": "Mangeur par couleur",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} combo par brique cassée la couleur de la balle, combo perdu sinon",
|
||||
|
@ -363,13 +410,15 @@
|
|||
"upgrades.slow_down.name": "Balle lente",
|
||||
"upgrades.slow_down.tooltip": "La balle se déplace plus lentement",
|
||||
"upgrades.slow_down.verbose_description": "La balle démarre relativement lentement, mais à chaque niveau de votre partie, elle démarre un peu plus vite, et elle accélère également si vous passez beaucoup de temps dans un niveau.\n\nCet avantage rend la balle plus facile à gérer. \n\nVous pouvez l'obtenir au début de chaque partie en activant le mode enfant dans le menu.",
|
||||
"upgrades.smaller_puck.help_plural": "La raquette rétrécie encore et le combo augmente encore.",
|
||||
"upgrades.smaller_puck.name": "Raquette plus petite",
|
||||
"upgrades.smaller_puck.tooltip": "Donne aussi +5 combo",
|
||||
"upgrades.smaller_puck.verbose_description": "Vous bénéficiez d'un bonus permanent de +5 combo pour avoir choisi cette amélioration.",
|
||||
"upgrades.smaller_puck.tooltip": "Donne également +{{percent}}% de pièces",
|
||||
"upgrades.smaller_puck.verbose_description": "Cela réduit la taille de la raquette, ce qui, en théorie, facilite certains tirs en coin, mais augmente en réalité la difficulté.\n\nC'est pourquoi vous obtenez également un bonus intéressant de +50 % d'apparition de pièces.",
|
||||
"upgrades.soft_reset.name": "Réinitialisation progressive",
|
||||
"upgrades.soft_reset.tooltip": "La remise à zéro du combo conserve {{percent}}% des points",
|
||||
"upgrades.soft_reset.verbose_description": "Limite l'impact d'une réinitialisation du combo.",
|
||||
"upgrades.sticky_coins.name": "Pièces collantes",
|
||||
"upgrades.sticky_coins.tooltip": "Les pièces collent aux briques de la même couleur",
|
||||
"upgrades.sticky_coins.verbose_description": "",
|
||||
"upgrades.streak_shots.name": "Séquence de destruction",
|
||||
"upgrades.streak_shots.tooltip": "Plus de pièces si vous cassez plusieurs briques à la fois.",
|
||||
"upgrades.streak_shots.verbose_description": "Chaque fois que vous cassez une brique, votre combo augmente. Le combo est remis à zéro quand la balle touche la raquette. Une fois que votre combo dépasse la valeur de base, votre raquette devient rouge pour vous rappeler que le fait de la toucher avec la balle détruira votre combo.",
|
||||
|
@ -383,6 +432,9 @@
|
|||
"upgrades.telekinesis.name": "Télékinésie",
|
||||
"upgrades.telekinesis.tooltip": "Contrôler la trajectoire de la balle",
|
||||
"upgrades.telekinesis.verbose_description": "Vous contrôlez la balle pendant qu'elle monte.",
|
||||
"upgrades.three_cushion.name": "Trois coussins",
|
||||
"upgrades.three_cushion.tooltip": "+1 combo par coup sur les côtés et le dessus, jusqu'à +{{max}} par rebond de la raquette. Le combo se réinitialise lorsque vous touchez une brique sans rebondir au préalable.",
|
||||
"upgrades.three_cushion.verbose_description": "Chaque coup porté d'un côté augmente le combo d'un point, jusqu'à +3. Après cela, aucun combo ne sera obtenu jusqu'au prochain rebond de la raquette.",
|
||||
"upgrades.top_is_lava.name": "Icare ",
|
||||
"upgrades.top_is_lava.tooltip": "+{{lvl}} combo par brique, perdu en cas de rebond au plafond",
|
||||
"upgrades.top_is_lava.verbose_description": "Chaque fois que vous cassez une brique, votre combo augmente d'une unité. Cependant, votre combo sera réinitialisé dès que votre balle atteindra le haut de l'écran.\n\nLorsque votre combo est supérieur au minimum, une barre rouge apparaît en haut de l'écran pour vous rappeler que vous devez éviter de la frapper.",
|
||||
|
@ -390,7 +442,7 @@
|
|||
"upgrades.trampoline.tooltip": "+{{lvl}} combo à chaque rebond d'une balle sur la raquette,-{{lvl}} combo à chaque rebond sur un des bords",
|
||||
"upgrades.trampoline.verbose_description": "Une des rares améliorations à ne pas avoir de condition de remise à zéro",
|
||||
"upgrades.transparency.name": "Camouflage",
|
||||
"upgrades.transparency.tooltip": "Plus la balle est haut à l'écran, plus elle devient transparente. Plus elle est transparente, plus elle produit de pièces.",
|
||||
"upgrades.transparency.tooltip": "La balle devient transparente en haut de l'écran. +{{percent}} % de pièces lorsque toutes les balles sont en transparence totale",
|
||||
"upgrades.transparency.verbose_description": "Les niveaux plus élevés rendent la balle transparente plus tôt et augmentent le bonus de points.",
|
||||
"upgrades.trickledown.name": "Ruissellement",
|
||||
"upgrades.trickledown.tooltip": "Les pièces apparaissent en haut de l'écran.",
|
||||
|
@ -405,10 +457,16 @@
|
|||
"upgrades.wind.name": "Vive le vent",
|
||||
"upgrades.wind.tooltip": "La position de la raquette crée du vent",
|
||||
"upgrades.wind.verbose_description": "Le vent dépend de la position de la raquette à l'écran, vers la gauche s'il est à gauche, vers la droite s'il est à droite. \nAffecte les balles et les pièces.",
|
||||
"upgrades.wrap_left.name": "",
|
||||
"upgrades.wrap_left.tooltip": "",
|
||||
"upgrades.wrap_left.verbose_description": "",
|
||||
"upgrades.wrap_right.name": "",
|
||||
"upgrades.wrap_right.tooltip": "",
|
||||
"upgrades.wrap_right.verbose_description": "",
|
||||
"upgrades.yoyo.name": "Yo-yo",
|
||||
"upgrades.yoyo.tooltip": "La balle se dirige vers la raquette en descendant.",
|
||||
"upgrades.yoyo.verbose_description": "C'est l'inverse de Télékinésie, contrôlez la balle alors qu'elle redescend vers la raquette.",
|
||||
"upgrades.zen.name": "Zen",
|
||||
"upgrades.zen.tooltip": "+{{lvl}} combo par brique, jusqu'à ce qu'il y ait une explosion",
|
||||
"upgrades.zen.verbose_description": "C'est quand même un jeu non violent à la base."
|
||||
"upgrades.zen.tooltip": "",
|
||||
"upgrades.zen.verbose_description": ""
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@ import fr from "./fr.json";
|
|||
import ar from "./ar.json";
|
||||
import ru from "./ru.json";
|
||||
import es from "./es.json";
|
||||
// import de from "./de.json";
|
||||
import tr from "./tr.json";
|
||||
import de from "./de.json";
|
||||
// import ko from "./ko.json";
|
||||
// import ur from "./ur.json";
|
||||
// import uz from "./uz.json";
|
||||
|
@ -14,7 +15,6 @@ export const languages = [
|
|||
text: "English",
|
||||
value: "en",
|
||||
strings: en,
|
||||
|
||||
levelName: "UK",
|
||||
},
|
||||
{
|
||||
|
@ -46,13 +46,19 @@ export const languages = [
|
|||
levelName: "Russia",
|
||||
},
|
||||
|
||||
// {
|
||||
// text: "Deutsch",
|
||||
// value: "de",
|
||||
// strings: de,
|
||||
//
|
||||
// levelName: "Germany",
|
||||
// },
|
||||
{
|
||||
text: "Deutsch",
|
||||
value: "de",
|
||||
strings: de,
|
||||
levelName: "Germany",
|
||||
},
|
||||
{
|
||||
text: "Türkçe",
|
||||
value: "tr",
|
||||
strings: tr,
|
||||
|
||||
levelName: "Türkiye",
|
||||
},
|
||||
// {
|
||||
// text: "汉语",
|
||||
// value: "zh",
|
||||
|
|
|
@ -3,6 +3,29 @@
|
|||
"confirmRestart.text": "Вы собираетесь начать новую игру. Вы уверены, что хотите продолжить?",
|
||||
"confirmRestart.title": "Начать новую игру?",
|
||||
"confirmRestart.yes": "Перезапустите игру",
|
||||
"editor.editing.bigger": "Увеличить размер уровня",
|
||||
"editor.editing.color": "Выберите цвет из списка цветов (максимум 5 на уровень)",
|
||||
"editor.editing.copy": "Скопировать код уровня",
|
||||
"editor.editing.copy_help": "Вставьте его в канал #levels в нашем Discord",
|
||||
"editor.editing.credit": "Кредиты и источник",
|
||||
"editor.editing.credit_prompt": "Введите исходный URL-адрес или пояснение вашего уровня.",
|
||||
"editor.editing.delete": "Удалить уровень",
|
||||
"editor.editing.down": "Сдвиньте все кирпичи вниз.",
|
||||
"editor.editing.help": "Затем щелкните по плитке, чтобы раскрасить ее.",
|
||||
"editor.editing.left": "Переместите все кирпичи влево.",
|
||||
"editor.editing.play": "Пройти этот уровень",
|
||||
"editor.editing.rename": "Название уровня",
|
||||
"editor.editing.rename_prompt": "Введите новое название уровня.",
|
||||
"editor.editing.right": "Переместите все кирпичи вправо.",
|
||||
"editor.editing.smaller": "Уменьшить размер уровня",
|
||||
"editor.editing.title": "Уровень редактирования: {{name}}",
|
||||
"editor.editing.up": "Поднимите все кирпичи.",
|
||||
"editor.help": "Создавайте собственные уровни и делитесь ими для включения в игру.",
|
||||
"editor.import": "Импортировать уровень",
|
||||
"editor.import_instruction": "Вставьте код уровня, чтобы импортировать его в список уровней.",
|
||||
"editor.locked": "Наберите в общей сложности {{min}} очков, чтобы разблокировать",
|
||||
"editor.new_level": "Новый уровень",
|
||||
"editor.title": "Редактор уровней",
|
||||
"gameOver.creative": "Этот забег не будет записываться.",
|
||||
"gameOver.cumulative_total": "Ваш общий суммарный балл увеличился с {{startTs}} до {{endTs}}.",
|
||||
"gameOver.lost.summary": "Вы уронили мяч, поймав {{score}} монет.",
|
||||
|
@ -32,12 +55,14 @@
|
|||
"history.columns.score": "Оценка",
|
||||
"history.columns.started": "Дата",
|
||||
"history.help": "Посмотрите свои {{count}} лучшие игры.",
|
||||
"history.include_past_versions": "",
|
||||
"history.locked": "Сыграйте не менее десяти игр, чтобы разблокировать",
|
||||
"history.title": "История побегов",
|
||||
"lab.help": "Попробуйте любую сборку.",
|
||||
"lab.instructions": "Выберите апгрейды ниже, а затем выберите уровень для игры.",
|
||||
"lab.instructions": "Выберите улучшения и уровень, затем нажмите кнопку воспроизведения выше.",
|
||||
"lab.menu_entry": "Творческий режим",
|
||||
"lab.reset": "Сбросить все в 0",
|
||||
"lab.play": "Играть",
|
||||
"lab.reset": "Перезагрузить",
|
||||
"lab.select_level": "Выберите уровень для игры",
|
||||
"lab.unlocks_at": "Открывается при общем количестве очков {{score}}",
|
||||
"level_up.after_buttons": "Вы только что закончили уровень {{level}}/{{max}}.",
|
||||
|
@ -139,6 +164,8 @@
|
|||
"score_panel.title": "{{score}} очков на уровне {{level}}/{{max}} ",
|
||||
"score_panel.upcoming_levels": "Предстоящие уровни :",
|
||||
"score_panel.upgrades_picked": "Обновления, выбранные в этой игре, запускаются :",
|
||||
"settings.autoplay": "Автоматическое воспроизведение",
|
||||
"settings.autoplay_help": "Начните сеанс со случайными улучшениями и компьютерным веслом",
|
||||
"settings.basic": "Базовая графика",
|
||||
"settings.basic_help": "Улучшенная производительность.",
|
||||
"settings.colorful_coins": "Разноцветные монеты",
|
||||
|
@ -163,12 +190,14 @@
|
|||
"settings.load_save_file_help": "Выберите файл сохранения на вашем устройстве",
|
||||
"settings.max_coins": " {{max}} монет на экране максимум",
|
||||
"settings.max_coins_help": "Только косметика, не влияет на результат",
|
||||
"settings.max_particles": " {{max}} частиц максимум",
|
||||
"settings.max_particles_help": "Ограничивает количество частиц, отображаемых на экране для визуального эффекта.",
|
||||
"settings.mobile": "Мобильный режим",
|
||||
"settings.mobile_help": "Оставляет место под лопаткой.",
|
||||
"settings.pointer_lock": "Блокировка указателя мыши",
|
||||
"settings.pointer_lock_help": "Фиксирует и скрывает курсор мыши.",
|
||||
"settings.precise_lighting": "Точное освещение",
|
||||
"settings.precise_lighting_help": "Используйте меньшую сетку для эффекта фонового освещения.",
|
||||
"settings.probabilistic_lighting": "Постоянство видения",
|
||||
"settings.probabilistic_lighting_help": "Улучшить производительность при наличии более 150 монет за счет повторного использования части света предыдущего кадра.",
|
||||
"settings.record": "Запись видеороликов игрового процесса",
|
||||
"settings.record_download": "Скачать видео ({{size}} МБ)",
|
||||
"settings.record_help": "Получите видеозапись каждого уровня.",
|
||||
|
@ -187,24 +216,30 @@
|
|||
"settings.show_fps_help": "Контролируйте работу приложения",
|
||||
"settings.show_stats": "Показывайте статистику в реальном времени",
|
||||
"settings.show_stats_help": "Монеты, время, отскоки, промахи",
|
||||
"settings.smooth_lighting": "Плавное освещение",
|
||||
"settings.smooth_lighting_help": "Размыть фоновые световые эффекты, чтобы они выглядели менее квадратными. Увеличивает задержку.",
|
||||
"settings.sounds": "Звуки игры",
|
||||
"settings.sounds_help": "Может замедлять работу некоторых телефонов.",
|
||||
"settings.sounds_help": "Бипы, блепы и брррр",
|
||||
"settings.stress_test": "Стресс-тест",
|
||||
"settings.stress_test_help": "Запустите игру, управляемую ботом, с очень большим количеством монет, чтобы проверить пределы производительности вашего устройства.",
|
||||
"starting_perks.checked": "Когда вы начнете новую игру, вам будет дано одно из этих преимуществ. Щелкните по перку, чтобы исключить его.",
|
||||
"starting_perks.help": "Выберите возможные стартовые апгрейды",
|
||||
"starting_perks.random": "Все преимущества были убраны, выбор будет случайным.",
|
||||
"starting_perks.title": "Стартовые привилегии",
|
||||
"starting_perks.unchecked": "Приведенные ниже привилегии не предлагаются в качестве стартовых, но вы можете нажать на них, чтобы добавить в пул.",
|
||||
"unlocks.greyed_out_help": "Выделенные серым апгрейды можно разблокировать, увеличив общее количество очков. Общий счет увеличивается каждый раз, когда вы набираете очки в игре.",
|
||||
"unlocks.intro": "Ваш общий счет составляет {{ts}}. Ниже представлены все обновления и уровни, которые предлагает игра. Нажмите на апгрейд или уровень ниже, чтобы начать тестовую игру с ним.",
|
||||
"unlocks.intro": "",
|
||||
"unlocks.just_unlocked": "Уровень разблокирован",
|
||||
"unlocks.just_unlocked_plural": "Вы только что разблокировали {{count}} уровней",
|
||||
"unlocks.level": "<h2>Вы разблокировали {{unlocked}} уровней из {{out_of}}</h2>\n<p>Здесь представлены все уровни игры, нажмите на один из них, чтобы опробовать его.</p> ",
|
||||
"unlocks.level": "",
|
||||
"unlocks.level_description": "Уровень {{size}}x{{size}} с {{bricks}} кирпичами, {{colors}} цветами и {{bombs}} бомбами.",
|
||||
"unlocks.levels": "",
|
||||
"unlocks.minScore": "Достигните ${{minScore}} в беге, чтобы разблокировать игру.",
|
||||
"unlocks.minScoreWithPerks": "Достигните ${{minScore}} в беге с {{required}} , но без {{forbidden}} для разблокировки.",
|
||||
"unlocks.minTotalScore": "Накопите в общей сложности ${{score}}",
|
||||
"unlocks.reached": "Ваш лучший результат - {{reached}}.",
|
||||
"unlocks.title_upgrades": "Вы разблокировали {{unlocked}} обновлений из {{out_of}}",
|
||||
"unlocks.upgrades": "",
|
||||
"upgrades.addiction.name": "Наркомания",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} комбо / кирпич, комбо сбрасывается на {{delay}}с после разрушения кирпича.",
|
||||
"upgrades.addiction.verbose_description": "Отсчет начинается только после разрушения первого кирпича на каждом уровне. Он остановится, как только все кирпичи будут уничтожены.",
|
||||
|
@ -237,6 +272,9 @@
|
|||
"upgrades.bricks_attract_coins.name": "Кирпичи притягивают монеты",
|
||||
"upgrades.bricks_attract_coins.tooltip": "Помогает им оставаться на вершине",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "Буй",
|
||||
"upgrades.buoy.tooltip": "Монеты плавают в течение {{duration}} секунд на нижней строке.",
|
||||
"upgrades.buoy.verbose_description": "Эффект наиболее заметен в мобильном режиме.",
|
||||
"upgrades.clairvoyant.name": "Ясновидящий",
|
||||
"upgrades.clairvoyant.tooltip": "Просматривайте предстоящие уровни, количество кирпичей и направление движения мяча",
|
||||
"upgrades.clairvoyant.verbose_description": "Поможет выбрать правильные апгрейды и понять, что происходит с прочными кирпичами. Уровни 2 и 3 дают дополнительные знания сомнительной полезности (достигаются в режиме цикла)",
|
||||
|
@ -253,6 +291,9 @@
|
|||
"upgrades.corner_shot.name": "Угловой удар",
|
||||
"upgrades.corner_shot.tooltip": "Позволяет накладывать паддл на границы экрана",
|
||||
"upgrades.corner_shot.verbose_description": "Помогает прицеливаться на поворотах. Дальние уровни позволят вам выйти дальше.",
|
||||
"upgrades.double_or_nothing.name": "",
|
||||
"upgrades.double_or_nothing.tooltip": "",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "Монеты, в космосе",
|
||||
"upgrades.etherealcoins.tooltip": "На монеты больше не действует гравитация",
|
||||
"upgrades.etherealcoins.verbose_description": "Монеты сохранят свою скорость даже после нескольких подпрыгиваний, и на них больше не будет действовать гравитация.",
|
||||
|
@ -268,10 +309,13 @@
|
|||
"upgrades.forgiving.verbose_description": "Первый промах за уровень - бесплатно, затем 10% от комбо, затем 20%.",
|
||||
"upgrades.fountain_toss.name": "Бросок фонтана",
|
||||
"upgrades.fountain_toss.tooltip": "Получите несколько комбо, когда пропустите несколько монет.",
|
||||
"upgrades.fountain_toss.verbose_description": "Если вы пропустили монету и ваша комбо была меньше {{max}}, то вероятность того, что ваша комбо вырастет на {{lvl}}/ комбо вырастет на единицу.",
|
||||
"upgrades.fountain_toss.verbose_description": "Если вы пропустили монету, а ваша комбинация была ниже уровня*30, у вашей комбинации есть вероятность того, что уровень/комбинация вырастет на единицу.",
|
||||
"upgrades.ghost_coins.name": "Призрачные монеты",
|
||||
"upgrades.ghost_coins.tooltip": "Монеты медленно проходят сквозь кирпичи",
|
||||
"upgrades.ghost_coins.verbose_description": "Это не ошибка, это особенность! Монеты пролетают сквозь кирпичи медленно. На более высоких уровнях они движутся быстрее.",
|
||||
"upgrades.happy_family.name": "",
|
||||
"upgrades.happy_family.tooltip": "",
|
||||
"upgrades.happy_family.verbose_description": "",
|
||||
"upgrades.helium.name": "Гелий",
|
||||
"upgrades.helium.tooltip": "Гравитация изменяется слева и справа от весла",
|
||||
"upgrades.helium.verbose_description": "Это повлияет на монеты и позволит им плавать до тех пор, пока вы не соберете их.",
|
||||
|
@ -308,8 +352,11 @@
|
|||
"upgrades.one_more_choice.name": "Дополнительный выбор",
|
||||
"upgrades.one_more_choice.tooltip": "При дальнейшем повышении уровня будет предложено на {{lvl}} больше вариантов в списке",
|
||||
"upgrades.one_more_choice.verbose_description": "В каждом меню апгрейдов появится еще одна опция. Это не увеличивает количество апгрейдов, которые вы можете выбрать.",
|
||||
"upgrades.ottawa_treaty.name": "Оттавский договор",
|
||||
"upgrades.ottawa_treaty.tooltip": "Разбивание кирпича рядом с бомбой обезвреживает ее.",
|
||||
"upgrades.ottawa_treaty.verbose_description": "Ближайшая бомба будет заменена цветным блоком. Если у вас есть сапер, мяч потеряет свой эффект сапера до следующего отскока. За один раз можно заменить только одну бомбу.",
|
||||
"upgrades.passive_income.name": "Пассивный доход",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} комбо/кирпич, если только паддл не двигался в течение последних {{time}}с, тогда он сбрасывается.",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} комбо / кирпич, весло не имеет значения {{time}}с после перемещения",
|
||||
"upgrades.passive_income.verbose_description": "Некоторые привилегии могут помочь шарам делать то, что вы хотите, без необходимости что-либо предпринимать.",
|
||||
"upgrades.picky_eater.name": "Придирчивый едок",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} комбо за каждый разбитый кирпич, сбрасывается при смене цвета шара",
|
||||
|
@ -363,13 +410,15 @@
|
|||
"upgrades.slow_down.name": "Медленный мяч",
|
||||
"upgrades.slow_down.tooltip": "Мяч движется медленнее",
|
||||
"upgrades.slow_down.verbose_description": "Мяч стартует относительно медленно, но с каждым уровнем вашей игры он будет стартовать все быстрее.\n\nОн также ускорится, если вы проведете много времени на одном уровне.\n\nЭто преимущество делает его более управляемым.\n\nВы можете получать его каждый раз в начале игры, включив детский режим в меню.",
|
||||
"upgrades.smaller_puck.help_plural": "Еще меньшее весло и более высокий базовый комбо",
|
||||
"upgrades.smaller_puck.name": "Маленькое весло",
|
||||
"upgrades.smaller_puck.tooltip": "Также дает +5 базовых комбо",
|
||||
"upgrades.smaller_puck.verbose_description": "Это уменьшает размер лепестка, что теоретически облегчает некоторые угловые удары, но на самом деле лишь повышает сложность игры.\n\nПоэтому вы также получите приятный бонус в виде +5 монет за кирпич за все кирпичи, которые вы разобьете после этого.",
|
||||
"upgrades.smaller_puck.tooltip": "Также дает +{{percent}}% монет",
|
||||
"upgrades.smaller_puck.verbose_description": "Это делает ракетку меньше, что в теории облегчает некоторые угловые удары, но на самом деле просто повышает сложность.\n\nВот почему вы также получаете приятный бонус в виде +50% появления монет.",
|
||||
"upgrades.soft_reset.name": "Мягкий сброс",
|
||||
"upgrades.soft_reset.tooltip": "Комбо-сброс сохраняет {{percent}}%",
|
||||
"upgrades.soft_reset.verbose_description": "Ограничьте влияние комбо-сброса.",
|
||||
"upgrades.sticky_coins.name": "Липкие монеты",
|
||||
"upgrades.sticky_coins.tooltip": "",
|
||||
"upgrades.sticky_coins.verbose_description": "",
|
||||
"upgrades.streak_shots.name": "Попадание в полосу",
|
||||
"upgrades.streak_shots.tooltip": "Больше монет, если вы разобьете много кирпичей, прежде чем подпрыгнуть на лопатке.",
|
||||
"upgrades.streak_shots.verbose_description": "Каждый раз, когда вы разбиваете кирпич, ваше комбо увеличивается на единицу.\n\nОднако как только мяч коснется вашего весла, комбо будет сброшено до стандартного значения.\n\nКак только ваше комбо поднимется выше базового значения, на лопатке появится красная рамка, напоминающая о том, что прикосновение мяча к ней уничтожит ваше комбо.",
|
||||
|
@ -383,6 +432,9 @@
|
|||
"upgrades.telekinesis.name": "Телекинез",
|
||||
"upgrades.telekinesis.tooltip": "Паддл управляет траекторией полета мяча",
|
||||
"upgrades.telekinesis.verbose_description": "Вы управляете мячом, пока он поднимается вверх.",
|
||||
"upgrades.three_cushion.name": "Три подушки",
|
||||
"upgrades.three_cushion.tooltip": "+1 комбо за удар по бокам и сверху, до +{{max}} за отскок весла. Комбо сбрасывается, когда вы ударяете кирпич без предварительного отскока.",
|
||||
"upgrades.three_cushion.verbose_description": "Каждый удар по стороне увеличит комбо на единицу, вплоть до +3. После этого комбо не будет набрано до следующего отскока ракетки.",
|
||||
"upgrades.top_is_lava.name": "Небо - это предел",
|
||||
"upgrades.top_is_lava.tooltip": "+{{lvl}} комбо за кирпич, сбрасывается при ударе сверху",
|
||||
"upgrades.top_is_lava.verbose_description": "Каждый раз, когда вы разбиваете кирпич, ваше комбо увеличивается на один. Однако, как только ваш мяч попадет в верхнюю часть экрана, комбо обнуляется.\n\nКогда ваше комбо превысит минимальное значение, вверху появится красная полоска, напоминающая о том, что вам следует избегать ударов.",
|
||||
|
@ -390,7 +442,7 @@
|
|||
"upgrades.trampoline.tooltip": "+{{lvl}} комбо за отскок, -{{lvl}} комбо за отскок на любой границе",
|
||||
"upgrades.trampoline.verbose_description": "Одно из редких комбо-улучшений, которое не добавляет условие сброса.",
|
||||
"upgrades.transparency.name": "Прозрачность",
|
||||
"upgrades.transparency.tooltip": "Чем выше шарик находится на экране, тем прозрачнее он становится. Чем прозрачнее шар, тем больше монет он приносит.",
|
||||
"upgrades.transparency.tooltip": "Мяч становится прозрачным в верхней части экрана. +{{percent}} % монет, когда все шары полностью прозрачны",
|
||||
"upgrades.transparency.verbose_description": "Более высокие уровни делают шар прозрачным быстрее и увеличивают бонус за очки.",
|
||||
"upgrades.trickledown.name": "Экономика по принципу \"копеечной монеты",
|
||||
"upgrades.trickledown.tooltip": "Монеты появляются в верхней части экрана.",
|
||||
|
@ -405,10 +457,16 @@
|
|||
"upgrades.wind.name": "Ветер",
|
||||
"upgrades.wind.tooltip": "Положение весла создает ветер",
|
||||
"upgrades.wind.verbose_description": "Ветер зависит от положения лопасти: левая дует влево, правая - вправо. Влияет как на шарики, так и на монеты.",
|
||||
"upgrades.wrap_left.name": "",
|
||||
"upgrades.wrap_left.tooltip": "",
|
||||
"upgrades.wrap_left.verbose_description": "",
|
||||
"upgrades.wrap_right.name": "",
|
||||
"upgrades.wrap_right.tooltip": "",
|
||||
"upgrades.wrap_right.verbose_description": "",
|
||||
"upgrades.yoyo.name": "Йо-йо",
|
||||
"upgrades.yoyo.tooltip": "Мяч падает на лопатку",
|
||||
"upgrades.yoyo.verbose_description": "Это противоположность телекинезу: управляйте мячом, пока он падает обратно.",
|
||||
"upgrades.zen.name": "Дзен",
|
||||
"upgrades.zen.tooltip": "+{{lvl}} комбо за кирпич, сбрасывается при взрыве",
|
||||
"upgrades.zen.verbose_description": "В конце концов, это ненасильственная игра."
|
||||
"upgrades.zen.tooltip": "",
|
||||
"upgrades.zen.verbose_description": ""
|
||||
}
|
||||
|
|
472
src/i18n/tr.json
Normal file
472
src/i18n/tr.json
Normal file
|
@ -0,0 +1,472 @@
|
|||
{
|
||||
"confirmRestart.no": "İptal etmek",
|
||||
"confirmRestart.text": "Yeni bir oyuna başlamak üzeresiniz. Devam etmek istediğinizden emin misiniz?",
|
||||
"confirmRestart.title": "Yeni bir oyuna mı başlasam?",
|
||||
"confirmRestart.yes": "Oyunu yeniden başlat",
|
||||
"editor.editing.bigger": "Seviye boyutunu artır",
|
||||
"editor.editing.color": "Renk listesinden bir renk seçin (seviye başına en fazla 5)",
|
||||
"editor.editing.copy": "Kopyalama seviyesi kodu",
|
||||
"editor.editing.copy_help": "Bunu Discord'umuzdaki #levels kanalına yapıştırın",
|
||||
"editor.editing.credit": "Krediler ve kaynak",
|
||||
"editor.editing.credit_prompt": "Seviyenizin kaynak URL'sini veya açıklamasını girin.",
|
||||
"editor.editing.delete": "Seviyeyi Sil",
|
||||
"editor.editing.down": "Tüm tuğlaları aşağı doğru hareket ettirin",
|
||||
"editor.editing.help": "Daha sonra renklendirmek istediğiniz kutucuğa tıklayın.",
|
||||
"editor.editing.left": "Tüm tuğlaları sola taşı",
|
||||
"editor.editing.play": "Bu seviyeyi oyna",
|
||||
"editor.editing.rename": "Seviye Adı",
|
||||
"editor.editing.rename_prompt": "Lütfen seviye için yeni bir ad girin",
|
||||
"editor.editing.right": "Tüm tuğlaları sağa taşı",
|
||||
"editor.editing.smaller": "Seviye boyutunu azalt",
|
||||
"editor.editing.title": "Düzenleme düzeyi : {{name}}",
|
||||
"editor.editing.up": "Tüm tuğlaları yukarı taşı",
|
||||
"editor.help": "Özel seviyeler yaratın ve bunları oyuna dahil etmek için paylaşın.",
|
||||
"editor.import": "Bir seviyeyi içe aktar",
|
||||
"editor.import_instruction": "Seviye listenize aktarmak için bir seviye kodunu yapıştırın",
|
||||
"editor.locked": "Kilidi açmak için toplam {{min}} puanına ulaşın",
|
||||
"editor.new_level": "Yeni seviye",
|
||||
"editor.title": "Seviye Editörü",
|
||||
"gameOver.creative": "Bu koşu kaydedilmeyecek.",
|
||||
"gameOver.cumulative_total": "Toplam kümülatif puanınız {{startTs}} 'dan {{endTs}}'e çıktı.",
|
||||
"gameOver.lost.summary": " {{score}} jeton yakaladıktan sonra topu düşürdün.",
|
||||
"gameOver.lost.title": "Oyun bitti",
|
||||
"gameOver.stats.balls_lost": "Kaybedilen toplar",
|
||||
"gameOver.stats.bricks_broken": "Tuğlalar kırıldı",
|
||||
"gameOver.stats.bricks_per_minute": "Dakikada kırılan tuğla sayısı",
|
||||
"gameOver.stats.catch_rate": "Yakalama oranı",
|
||||
"gameOver.stats.combo_avg": "Ortalama kombo",
|
||||
"gameOver.stats.combo_max": "Maksimum kombo",
|
||||
"gameOver.stats.duration_per_level": "Seviye başına süre",
|
||||
"gameOver.stats.hit_rate": "İsabet oranı",
|
||||
"gameOver.stats.intro": "",
|
||||
"gameOver.stats.level_reached": "Seviyeye ulaşıldı",
|
||||
"gameOver.stats.total_score": "Toplam Puan",
|
||||
"gameOver.stats.upgrades_applied": "Uygulanan yükseltmeler",
|
||||
"gameOver.stats_intro": "Aşağıda {{count}} en iyi oyunlarınızla karşılaştırıldığında oyun istatistiklerinizi bulabilirsiniz.",
|
||||
"gameOver.unlocked_perk": "Yükseltme kilidi açıldı",
|
||||
"gameOver.unlocked_perk_plural": "Az önce {{count}} avantajın kilidini açtınız",
|
||||
"gameOver.win.summary": "Bu oyun bitti. {{score}} jeton sakladın.",
|
||||
"gameOver.win.title": "Bu oyunu tamamladın",
|
||||
"help.content": "## Hedef\n\n7 seviye boyunca mümkün olduğunca çok jeton topla. \nTuğlaları kırdığında jetonlar belirir.\nPuanını artırmak için küreğinle topla.\nPuanın ekranın sağ üst köşesinde gösterilir.\nTopu düşürme yoksa oyun biter.\n\nTüm tuğlaları yok ettikten sonra bir yükseltme seçebilirsin.\n\n## Yükseltmeler \n\nSeçtiğin yükseltmeler koşunun sonuna kadar geçerli olur. \nBazıları daha güçlü etki için birden fazla kez seçilebilir.\nBazıları nişan almaya yardımcı olur veya oyunu başka şekillerde kolaylaştırır. \nBazıları yalnızca birleştirildiğinde işe yarar.\n\nHer oyunun başında her zaman bir yükseltme alırsın. \nSimgesi ilk seviyenin tuğlaları olarak hizmet eder. \nAyarlardan başlangıç yükseltmelerini seçebilirsin.\n\nBirçok yükseltme kombonu etkiler. \n\n## Kombo\n\n\"Kombon\", bir tuğla kırıldığında ortaya çıkan jeton sayısıdır. \nKüreğinizde görüntülenir, örneğin x4 her tuğlanın 4 jeton üreteceği anlamına gelir. \nKomboyu artıran çoğu yükseltme, onu sıfırlamak için bir koşul da ekler. \nTop herhangi bir tuğlaya çarpmadan küreğe geri dönerse kombo da sıfırlanır. \nBu olduğunda bir \"ıskalama\" mesajı gösterilir. \n\nHer seferinde bir tuğlaya doğru nişan almaya çalışın. \n\n## Nişan Alma\n\nSadece küreğin üzerindeki top konumu nasıl sekeceğine karar verir. \nTop küreğin tam ortasına çarparsa, dikey olarak geri sekecektir. \nBir tarafa daha fazla vurursanız, daha fazla açıya sahip olacaktır. \nKürek hızı ve gelen açı, zıpladıktan sonra topun yönü üzerinde hiçbir etkiye sahip değildir. \n\nNişan almaya yardımcı olan birçok yükseltme açılabilir. \n\n## Kilit Açmalar\n\nBreakout 71'i ilk kez oynarken, çoğu yükseltme ve seviye kilitlenir. \nYükseltmeler, sadece oynayarak ve birçok jeton yakalayarak açılır. \nİlk seviyeler yüksek bir puana ulaşarak açılır.\nDaha sonraki seviyeler hangi avantajları seçebileceğinize dair bir koşul ekler.\n\nHer seviyeden sonra birden fazla yükseltme aldığınızda yüksek puanlara ulaşmak çok daha kolaydır.\n\n## Tekrar atışlar ve ücretsiz yükseltmeler\n\nİyi oynadığınızda seçebileceğiniz ekstra bir yükseltme elde edersiniz: \n\n- Seviyeyi {{levelTimeGood}} saniyenin altında tamamlayın\n- Kenarlara veya tepeye {{wallBouncedGood}} kereden az vurun\n- Paraların {{catchRateGood}}%'sini yakalayın\n- Tuğlaları {{missesGood}} kereden az ıskalayın\n\nDaha da iyi yaparsanız yükseltmeleri atlamanıza izin veren bir tekrar atış da elde edersiniz: \n\n- Seviyeyi {{levelTimeBest}} saniyenin altında tamamlayın\n- Kenarlara veya tepeye {{wallBouncedBest}} kereden az vurun\n- Paraların {{catchRateBest}}%'sini yakalayın\n- Tuğlaları {{missesBest}} kereden az ıskalayın\n\nAyarlardaki bir seçenek bu istatistikleri görüntülemenizi sağlar",
|
||||
"help.help": "Oyun hakkında daha fazla bilgi edinin",
|
||||
"help.levels": "Seviyeler",
|
||||
"help.title": "Yardım",
|
||||
"help.upgrades": "## Yükseltmeler",
|
||||
"history.columns.score": "Gol",
|
||||
"history.columns.started": "Tarih",
|
||||
"history.help": "En iyi {{count}} oyununuzu görün.",
|
||||
"history.include_past_versions": "",
|
||||
"history.locked": "Kilidi açmak için en az on oyun oynayın",
|
||||
"history.title": "Koşu geçmişi",
|
||||
"lab.help": "İstediğiniz herhangi bir yapıyı deneyin",
|
||||
"lab.instructions": "Yükseltmeleri ve bir seviyeyi seçin, ardından yukarıdaki oynat düğmesine tıklayın",
|
||||
"lab.menu_entry": "Yaratıcı mod",
|
||||
"lab.play": "Oynamak",
|
||||
"lab.reset": "Sıfırla",
|
||||
"lab.select_level": "Oynamak için bir seviye seçin",
|
||||
"lab.unlocks_at": "Toplam puan {{score}}olduğunda açılır",
|
||||
"level_up.after_buttons": " {{level}}/{{max}}seviyesini yeni bitirdiniz.",
|
||||
"level_up.before_buttons": " {{time}} saniyede {{levelSpawnedCoins}} üzerinden {{score}} jeton {{catchGain}} yakaladın {{timeGain}}.\n {{levelMisses}} kez {{missesGain}} ıskaladın ve {{levelWallBounces}} kez duvarlara veya tavana çarptın{{wallHitsGain}}.\n{{compliment}}",
|
||||
"level_up.compliment_advice": "Tüm paraları toplamaya çalışın, tuğlaları asla kaçırmayın, duvarlara/tavana çarpmayın veya ek yükseltmeler kazanmak için 30 saniyenin altındaki seviyeyi temizlemeyin.",
|
||||
"level_up.compliment_good": "Tebrikler !",
|
||||
"level_up.compliment_perfect": "Çok etkileyici, böyle devam edin!",
|
||||
"level_up.pick_upgrade_title": "Bir yükseltme seçin",
|
||||
"level_up.plus_one_upgrade": "(+1 yükseltme)",
|
||||
"level_up.plus_one_upgrade_and_reroll": "(+1 yükseltme ve +1 yeniden atma)",
|
||||
"level_up.reroll": "Tekrar at ({{count}})",
|
||||
"level_up.reroll_help": "Yeni seçenekler sunun",
|
||||
"level_up.upgrade_perk_to_level": "Seviye {{level}}",
|
||||
"main_menu.basic": "",
|
||||
"main_menu.basic_help": "",
|
||||
"main_menu.colorful_coins": "",
|
||||
"main_menu.colorful_coins_help": "",
|
||||
"main_menu.comboIncreaseTexts": "",
|
||||
"main_menu.comboIncreaseTexts_help": "",
|
||||
"main_menu.contrast": "",
|
||||
"main_menu.contrast_help": "",
|
||||
"main_menu.credit_levels": "",
|
||||
"main_menu.donate": " {{hours}} saat oynadınız",
|
||||
"main_menu.donate_help": "Bağış yapmaya ne dersiniz? Ayarlardan bu hatırlatıcıyı gizleyebilirsiniz.",
|
||||
"main_menu.donation_reminder": "",
|
||||
"main_menu.donation_reminder_help": "",
|
||||
"main_menu.download_save_file": "",
|
||||
"main_menu.download_save_file_help": "",
|
||||
"main_menu.extra_bright": "",
|
||||
"main_menu.extra_bright_help": "",
|
||||
"main_menu.fullscreen": "",
|
||||
"main_menu.fullscreen_help": "",
|
||||
"main_menu.help_content": "",
|
||||
"main_menu.help_help": "",
|
||||
"main_menu.help_title": "",
|
||||
"main_menu.help_upgrades": "",
|
||||
"main_menu.high_score": "En yüksek puan : {{score}}",
|
||||
"main_menu.kid": "",
|
||||
"main_menu.kid_help": "",
|
||||
"main_menu.language": "",
|
||||
"main_menu.language_help": "",
|
||||
"main_menu.load_save_file": "",
|
||||
"main_menu.load_save_file_help": "",
|
||||
"main_menu.max_coins": "",
|
||||
"main_menu.max_coins_help": "",
|
||||
"main_menu.max_particles": "",
|
||||
"main_menu.max_particles_help": "",
|
||||
"main_menu.mobile": "",
|
||||
"main_menu.mobile_help": "",
|
||||
"main_menu.normal": "Yeni Oyun",
|
||||
"main_menu.normal_help": "Rastgele bir başlangıç avantajıyla 7 seviye oynayın",
|
||||
"main_menu.pointer_lock": "",
|
||||
"main_menu.pointer_lock_help": "",
|
||||
"main_menu.record": "",
|
||||
"main_menu.record_download": "",
|
||||
"main_menu.record_help": "",
|
||||
"main_menu.red_miss": "",
|
||||
"main_menu.red_miss_help": "",
|
||||
"main_menu.reset": "",
|
||||
"main_menu.reset_cancel": "",
|
||||
"main_menu.reset_confirm": "",
|
||||
"main_menu.reset_help": "",
|
||||
"main_menu.reset_instruction": "",
|
||||
"main_menu.save_file_error": "",
|
||||
"main_menu.save_file_loaded": "",
|
||||
"main_menu.save_file_loaded_help": "",
|
||||
"main_menu.save_file_loaded_ok": "",
|
||||
"main_menu.settings_help": "Oyun tarzını ihtiyaçlarınıza ve zevkinize göre uyarlayın",
|
||||
"main_menu.settings_title": "Ayarlar",
|
||||
"main_menu.show_fps": "",
|
||||
"main_menu.show_fps_help": "",
|
||||
"main_menu.show_stats": "",
|
||||
"main_menu.show_stats_help": "",
|
||||
"main_menu.sounds": "",
|
||||
"main_menu.sounds_help": "",
|
||||
"main_menu.starting_perks": "",
|
||||
"main_menu.starting_perks_checked": "",
|
||||
"main_menu.starting_perks_full_random": "",
|
||||
"main_menu.starting_perks_help": "",
|
||||
"main_menu.starting_perks_unchecked": "",
|
||||
"main_menu.title": "Kopuş 71",
|
||||
"main_menu.unlocks": "Kilidi açılmış içerik",
|
||||
"main_menu.unlocks_help": "Kilidini açtığınız avantajları ve seviyeleri deneyin",
|
||||
"play.close_modale_window_tooltip": "Kapalı",
|
||||
"play.current_lvl": "Seviye {{level}}/{{max}}",
|
||||
"play.menu_label": "Menü",
|
||||
"play.menu_tooltip": "Ana menüyü aç",
|
||||
"play.missed_ball": "Kayıp",
|
||||
"play.mobile_press_to_play": "Oynamak için buraya basın ve basılı tutun",
|
||||
"play.score_tooltip": "Puanınızı, yükseltmelerinizi ve daha fazlasını görün",
|
||||
"play.stats.coins_catch_rate": "Madeni para yakalama oranı",
|
||||
"play.stats.levelMisses": "Hiçbir şeye isabet ettiremediğiniz şutlar",
|
||||
"play.stats.levelTime": "Seviye zamanı",
|
||||
"play.stats.levelWallBounces": "Duvar sıçramaları",
|
||||
"score_panel.close_to_unlock": "Sonraki seviyenin kilidini aç:",
|
||||
"score_panel.get_upgrades_to_unlock": " {{missingUpgrades}} alın ve \"{{level}}\" seviyesinin kilidini açmak için {{points}} puan daha kazanın",
|
||||
"score_panel.rerolls_count": " {{rerolls}} yeniden atma biriktirdiniz",
|
||||
"score_panel.score_to_unlock": "\"{{level}}\" seviyesini açmak için {{points}} puan daha kazanın",
|
||||
"score_panel.title": " {{level}}/{{max}} seviyesinde{{score}} puan",
|
||||
"score_panel.upcoming_levels": "Yaklaşan seviyeler :",
|
||||
"score_panel.upgrades_picked": "Bu oyun çalışmasında seçilen yükseltmeler:",
|
||||
"settings.autoplay": "Otomatik oynatma",
|
||||
"settings.autoplay_help": "Rastgele yükseltmeler ve bilgisayar kontrollü bir kürekle bir oturum başlatın",
|
||||
"settings.basic": "Temel grafikler",
|
||||
"settings.basic_help": "Daha iyi performans.",
|
||||
"settings.colorful_coins": "Renkli madeni paralar",
|
||||
"settings.colorful_coins_help": "Madeni paralar her zaman tuğlanın renginde ortaya çıkar",
|
||||
"settings.comboIncreaseTexts": "Altında +X göster",
|
||||
"settings.comboIncreaseTexts_help": "Kombo arttığında",
|
||||
"settings.contrast": "Yüksek Kontrast",
|
||||
"settings.contrast_help": "Daha renkli ve koyu görüntü oluşturma",
|
||||
"settings.donation_reminder": "Bana bağış yapmayı hatırlat",
|
||||
"settings.donation_reminder_help": "Oynanan süreyi ve bağış bağlantısını ana menüde görün",
|
||||
"settings.download_save_file": "Puan ve istatistikleri indir",
|
||||
"settings.download_save_file_help": "Bir kayıt dosyası al",
|
||||
"settings.extra_bright": "Ekstra parlak",
|
||||
"settings.extra_bright_help": "Madeni paraların ve tuğlaların etrafındaki hale boyutunu büyütür.",
|
||||
"settings.fullscreen": "Tam ekran",
|
||||
"settings.fullscreen_help": "Oyun başlamadan önce tam ekran olmaya çalışacak",
|
||||
"settings.kid": "Çocuk modu",
|
||||
"settings.kid_help": "Gelecek oyunlara \"daha yavaş top\" ile başlayın.",
|
||||
"settings.language": "Dil",
|
||||
"settings.language_help": "Oyunun dilini seçin",
|
||||
"settings.load_save_file": "Kayıt dosyasını yükle",
|
||||
"settings.load_save_file_help": "Cihazınızda bir kayıt dosyası seçin",
|
||||
"settings.max_coins": "Ekranda maksimum {{max}} jeton var",
|
||||
"settings.max_coins_help": "Sadece kozmetik, puan üzerinde etkisi yok",
|
||||
"settings.mobile": "Mobil mod",
|
||||
"settings.mobile_help": "Kürek altında boşluk bırakır.",
|
||||
"settings.pointer_lock": "Fare işaretçisi kilidi",
|
||||
"settings.pointer_lock_help": "Fare imlecini kilitler ve gizler.",
|
||||
"settings.precise_lighting": "Hassas aydınlatma",
|
||||
"settings.precise_lighting_help": "Arka plan ışık efekti için daha küçük bir ızgara kullanın",
|
||||
"settings.probabilistic_lighting": "Vizyonun kalıcılığı",
|
||||
"settings.probabilistic_lighting_help": "Önceki karenin ışığının bir kısmını yeniden kullanarak 150'den fazla jeton olduğunda performansı iyileştirin",
|
||||
"settings.record": "Oyun videolarını kaydedin",
|
||||
"settings.record_download": "Videoyu indir ({{size}} MB)",
|
||||
"settings.record_help": "Her seviyenin videosunu edinin.",
|
||||
"settings.red_miss": "Uyarıyı kaçırdım",
|
||||
"settings.red_miss_help": "Vuruş yapmadan aşağı inen topların etrafında kırmızı parçacıklar göster.",
|
||||
"settings.reset": "Oyunu Sıfırla",
|
||||
"settings.reset_cancel": "HAYIR",
|
||||
"settings.reset_confirm": "Evet",
|
||||
"settings.reset_help": "En yüksek skoru, oyun süresini ve istatistikleri sil",
|
||||
"settings.reset_instruction": "Oyunda kaydettiğiniz tüm ilerlemeyi kaybedeceksiniz, emin misiniz?",
|
||||
"settings.save_file_error": "Kayıt dosyası yüklenirken hata oluştu",
|
||||
"settings.save_file_loaded": "Yüklenen dosya kaydedildi",
|
||||
"settings.save_file_loaded_help": "Uygulama şimdi kaydınızı uygulamak için yeniden yüklenecek",
|
||||
"settings.save_file_loaded_ok": "TAMAM",
|
||||
"settings.show_fps": "FPS Sayacı",
|
||||
"settings.show_fps_help": "Uygulamanın performansını izleyin",
|
||||
"settings.show_stats": "Gerçek zamanlı istatistikleri göster",
|
||||
"settings.show_stats_help": "Paralar, zaman, sekmeler, ıskalar",
|
||||
"settings.smooth_lighting": "Pürüzsüz aydınlatma",
|
||||
"settings.smooth_lighting_help": "Arka plan ışık efektlerini daha az kare görünmeleri için bulanıklaştırın. Gecikmeyi artırır.",
|
||||
"settings.sounds": "Oyun sesleri",
|
||||
"settings.sounds_help": "Bipler, blooplar ve brrrr",
|
||||
"settings.stress_test": "Stres testi",
|
||||
"settings.stress_test_help": "Cihazınızın performans sınırlarını test etmek için çok sayıda jetonla bot kontrollü bir oyun başlatın.",
|
||||
"starting_perks.checked": "Yeni bir oyuna başladığınızda, bu avantajlardan biri size verilecektir. Bir avantajı hariç tutmak için tıklayın.",
|
||||
"starting_perks.help": "Olası başlangıç yükseltmelerini seçin",
|
||||
"starting_perks.random": "Tüm avantajlar kaldırıldı, seçim rastgele olacak.",
|
||||
"starting_perks.title": "Başlangıç avantajları",
|
||||
"starting_perks.unchecked": "Aşağıdaki avantajlar başlangıç avantajı olarak sunulmamaktadır, ancak havuza eklemek için tıklayabilirsiniz.",
|
||||
"unlocks.greyed_out_help": "Grileştirilmiş yükseltmeler toplam puanınızı artırarak açılabilir. Toplam puan, oyunda her puan aldığınızda artar.",
|
||||
"unlocks.intro": "",
|
||||
"unlocks.just_unlocked": "Seviye kilidi açıldı",
|
||||
"unlocks.just_unlocked_plural": "Az önce {{count}} seviyenin kilidini açtınız",
|
||||
"unlocks.level": "",
|
||||
"unlocks.level_description": " {{bricks}} tuğla, {{colors}} renk ve {{bombs}} bombadan oluşan {{size}}x{{size}} büyüklüğünde bir seviye.",
|
||||
"unlocks.levels": "",
|
||||
"unlocks.minScore": "Kilidi açmak için bir koşuda ${{minScore}} 'a ulaşın.",
|
||||
"unlocks.minScoreWithPerks": " {{required}} ile ancak {{forbidden}} olmadan bir koşuda ${{minScore}} 'a ulaşın.",
|
||||
"unlocks.minTotalScore": "Toplam ${{score}}biriktirin",
|
||||
"unlocks.reached": "En iyi skorunuz {{reached}}idi.",
|
||||
"unlocks.title_upgrades": " {{out_of}}yükseltmeden {{unlocked}} tanesinin kilidini açtınız",
|
||||
"unlocks.upgrades": "",
|
||||
"upgrades.addiction.name": "Bağımlılık",
|
||||
"upgrades.addiction.tooltip": "+{{lvl}} kombo / tuğla, kombo bir tuğlayı kırdıktan sonra {{delay}}saniye içinde sıfırlanır.",
|
||||
"upgrades.addiction.verbose_description": "Geri sayım yalnızca her seviyenin ilk tuğlası kırıldıktan sonra başlar. Tüm tuğlalar yok edildiğinde durur.",
|
||||
"upgrades.asceticism.name": "Zühd",
|
||||
"upgrades.asceticism.tooltip": "+{{combo}} kombo / tuğla, - {{combo}} jeton yakalamada",
|
||||
"upgrades.asceticism.verbose_description": "Kombonuz tırmanırken paraları bir yere saklamanız gerekecek.",
|
||||
"upgrades.ball_attract_ball.help_plural": "Daha güçlü çekim kuvveti",
|
||||
"upgrades.ball_attract_ball.name": "Yer çekimi",
|
||||
"upgrades.ball_attract_ball.tooltip": "Toplar toplarını çeker",
|
||||
"upgrades.ball_attract_ball.verbose_description": "\"Oyun alanının genişliğinin 3/4'ünden\" daha uzakta olan toplar birbirini çekmeye başlayacaktır. \n\nÇekim kuvveti, birbirlerinden en uzakta olduklarında daha güçlüdür. \n\nGökkuşağı parçacıkları çekim kuvvetini sembolize etmek için uçacaktır. Bu avantaj yalnızca birden fazla topunuz varsa sunulur.",
|
||||
"upgrades.ball_attracts_coins.name": "Toplar madeni paraları çeker",
|
||||
"upgrades.ball_attracts_coins.tooltip": "Madeni paralar en yakın topu takip eder ve daha yavaş düşer",
|
||||
"upgrades.ball_attracts_coins.verbose_description": "\"Leke\" ve \"hayalet paralar\" ile birleştirdiğinizde, bu, paralarla topların \"etrafını boyamak\" için kullanılabilir. Ayrıca, para mıknatısı yerine de kullanılabilir.",
|
||||
"upgrades.ball_repulse_ball.help_plural": "Daha güçlü itme kuvveti",
|
||||
"upgrades.ball_repulse_ball.name": "Kişisel alan",
|
||||
"upgrades.ball_repulse_ball.tooltip": "Toplar topları iter",
|
||||
"upgrades.ball_repulse_ball.verbose_description": "Çeyrek ekran genişliğinden daha az uzaklıktaki toplar birbirini itmeye başlayacaktır. Birbirlerine yakınlarsa itme kuvveti daha güçlüdür. Parçacıklar bu kuvvetin uygulandığını sembolize etmek için dışarı fırlayacaktır. Bu avantaj yalnızca birden fazla topunuz varsa sunulur.",
|
||||
"upgrades.base_combo.name": "Güçlü temeller",
|
||||
"upgrades.base_combo.tooltip": "Kombo 1 yerine {{coins}} 'dan başlar.",
|
||||
"upgrades.base_combo.verbose_description": "Kombonuz normalde seviyenin başında 1'den başlar ve hiçbir şeye çarpmadan zıpladığınızda 1'e sıfırlanır. Bu avantajla, kombo 3 puan daha yüksekte başlar, bu yüzden her zaman tuğla başına en az 4 jeton alırsınız. Kombonuz her sıfırlandığında, 1 yerine 4'e geri döner. Topunuz, kombosunun birden yüksek olduğunu belirtmek için biraz parıldayacaktır.",
|
||||
"upgrades.bigger_explosions.name": "Kaboom",
|
||||
"upgrades.bigger_explosions.tooltip": "Daha büyük patlamalar",
|
||||
"upgrades.bigger_explosions.verbose_description": "Varsayılan patlama 3x3 kareyi temizler, bununla 5x5 kare olur ve paralara gelen darbe de önemli ölçüde daha güçlüdür. Ekran her patlamadan sonra yanıp söner (temel mod hariç)",
|
||||
"upgrades.bigger_puck.name": "Daha büyük kürek",
|
||||
"upgrades.bigger_puck.tooltip": "Kolayca daha fazla para yakalayın.",
|
||||
"upgrades.bigger_puck.verbose_description": "Daha büyük bir kürek, topu asla ıskalamamanızı ve daha fazla jeton yakalamanızı kolaylaştırır, ayrıca topun sekme açısını hassas bir şekilde ayarlamanızı sağlar (topun açısı yalnızca küreğe çarptığı yere bağlıdır).",
|
||||
"upgrades.bricks_attract_ball.name": "Tuğlalar topları çeker",
|
||||
"upgrades.bricks_attract_ball.tooltip": "Top çarpacağı ilk {{count}} tuğlaya doğru gider.",
|
||||
"upgrades.bricks_attract_ball.verbose_description": "Etkisi daha yüksek seviyelerde daha güçlüdür. Etki durmadan önce vurabilecek tuğla sayısı da daha yüksektir. Etki, top diske çarptığında yeniden silahlanır.",
|
||||
"upgrades.bricks_attract_coins.name": "Tuğlalar madeni paraları çeker",
|
||||
"upgrades.bricks_attract_coins.tooltip": "Onların orada kalmalarına yardımcı olur",
|
||||
"upgrades.bricks_attract_coins.verbose_description": "",
|
||||
"upgrades.buoy.name": "Şamandıra",
|
||||
"upgrades.buoy.tooltip": "Madeni paralar alt satırda {{duration}} saniye boyunca yüzer.",
|
||||
"upgrades.buoy.verbose_description": "Etkisi mobil modda en iyi şekilde görülür",
|
||||
"upgrades.clairvoyant.name": "Durugörü sahibi",
|
||||
"upgrades.clairvoyant.tooltip": "Yaklaşan seviyeleri, tuğla HP'sini ve top yönünü görün",
|
||||
"upgrades.clairvoyant.verbose_description": "Doğru yükseltmeleri seçmenize ve sağlam tuğlalarla neler olup bittiğini anlamanıza yardımcı olur. Seviye 2 ve 3, şüpheli fayda hakkında ek bilgi getirir (döngü modunda erişilebilir)",
|
||||
"upgrades.coin_magnet.help_plural": "Madeni paralar üzerinde daha güçlü etki",
|
||||
"upgrades.coin_magnet.name": "Madeni para mıknatısı",
|
||||
"upgrades.coin_magnet.tooltip": "Kürek paraları çekiyor",
|
||||
"upgrades.coin_magnet.verbose_description": "Madeni paraları küreğe yönlendirir. Madeni para zaten küreğe yakınsa etkisi daha güçlüdür.",
|
||||
"upgrades.compound_interest.name": "Bileşik faiz",
|
||||
"upgrades.compound_interest.tooltip": "+{{lvl}} kombo her kırılan tuğla için, jeton kaybedildiğinde sıfırlanır",
|
||||
"upgrades.compound_interest.verbose_description": "Her tuğlayı kırdığınızda kombonuz bir artacak ve kırdığınız her tuğlayla birlikte daha fazla jeton ortaya çıkacaktır. \nAncak, bu jetonların her birini küreğinizle yakaladığınızdan emin olun, çünkü kaybedilen jeton kombonuzu sıfırlayacaktır.\nKombonuz minimumun üzerine çıktığında, oyun alanının alt kısmında jetonların oraya gitmemesi gerektiğini hatırlatan kırmızı bir çizgi olacaktır.",
|
||||
"upgrades.concave_puck.name": "İçbükey kürek",
|
||||
"upgrades.concave_puck.tooltip": "Dikey nişan alma hassasiyetini artırır",
|
||||
"upgrades.concave_puck.verbose_description": "Toplar düz bir şekilde yukarı doğru çıkarak başlar ve daha az açıyla zıplar.",
|
||||
"upgrades.corner_shot.name": "Köşe vuruşu",
|
||||
"upgrades.corner_shot.tooltip": "Küreğinizin ekranın sınırlarıyla örtüşmesini sağlar",
|
||||
"upgrades.corner_shot.verbose_description": "Köşelerde nişan almaya yardımcı olur. Daha ileri seviyeler daha uzağa gitmenizi sağlar.",
|
||||
"upgrades.double_or_nothing.name": "",
|
||||
"upgrades.double_or_nothing.tooltip": "",
|
||||
"upgrades.double_or_nothing.verbose_description": "",
|
||||
"upgrades.etherealcoins.name": "Uzayda Madeni Paralar",
|
||||
"upgrades.etherealcoins.tooltip": "Madeni paralar artık yer çekiminden etkilenmiyor",
|
||||
"upgrades.etherealcoins.verbose_description": "Paralar birkaç kez zıpladıktan sonra bile hızlarını koruyacak ve artık yer çekiminden etkilenmeyecekler.",
|
||||
"upgrades.extra_levels.name": "5 dakika daha",
|
||||
"upgrades.extra_levels.tooltip": "7 yerine {{count}} seviye oyna",
|
||||
"upgrades.extra_levels.verbose_description": "Varsayılan oyun en fazla 7 seviye sürebilir, ardından oyun biter. \n\nBu avantajın her seviyesi bir seviye daha yukarı çıkmanızı sağlar. Son seviyeler genellikle en fazla puanı aldığınız seviyelerdir, bu yüzden fark dramatik olabilir.",
|
||||
"upgrades.extra_life.help_plural": "(Son) topunuz kaybolmak yerine ({{lvl}} kez) dipte sekecektir.",
|
||||
"upgrades.extra_life.name": "Ekstra Hayat",
|
||||
"upgrades.extra_life.tooltip": "Top, kaybedilmeden önce alt çizgide bir kez sekecektir.",
|
||||
"upgrades.extra_life.verbose_description": "Normalde bir topunuz vardır ve oyun onu bıraktığınız anda biter.\n\nBu yetenek, ekranın altına bir kez topu kurtaracak ve bu süreçte kırılacak beyaz bir çubuk ekler. \n\nEkranın altında bir top her zıpladığında bu yeteneğin bir seviyesini kaybedersiniz.",
|
||||
"upgrades.forgiving.name": "Bağışlayıcı",
|
||||
"upgrades.forgiving.tooltip": "Molaları kaçırmak, komboyu bir kerede azaltmak yerine kademeli olarak azaltır.",
|
||||
"upgrades.forgiving.verbose_description": "Her seviyede ilk ıskalama bedava, sonra kombonun %10'u, sonra %20'si...",
|
||||
"upgrades.fountain_toss.name": "Çeşme atışı",
|
||||
"upgrades.fountain_toss.tooltip": "Birkaç jetonu kaçırdığınızda bir miktar kombo kazanın.",
|
||||
"upgrades.fountain_toss.verbose_description": "Bir jetonu kaçırdığınızda ve kombonuz seviye*30'un altındaysa, kombonuzun seviye/kombo oranının bir artması olasılığı vardır.",
|
||||
"upgrades.ghost_coins.name": "Hayalet paralar",
|
||||
"upgrades.ghost_coins.tooltip": "Madeni paralar yavaşça tuğlaların arasından geçiyor",
|
||||
"upgrades.ghost_coins.verbose_description": "Bu bir hata değil, bir özellik! Madeni paralar tuğlaların içinden yavaşça uçar. Daha yüksek seviyeler daha hızlı hareket etmelerini sağlar.",
|
||||
"upgrades.happy_family.name": "",
|
||||
"upgrades.happy_family.tooltip": "",
|
||||
"upgrades.happy_family.verbose_description": "",
|
||||
"upgrades.helium.name": "Helyum",
|
||||
"upgrades.helium.tooltip": "Yerçekimi küreğin solunda ve sağında tersine döndü",
|
||||
"upgrades.helium.verbose_description": "Bu, paraları etkileyecek ve siz onları almaya hazır olana kadar paraların havada asılı kalmasına neden olacaktır.",
|
||||
"upgrades.hot_start.name": "Sıcak başlangıç",
|
||||
"upgrades.hot_start.tooltip": " {{start}}kombosundan başla, saniyede{{loss}} kombo",
|
||||
"upgrades.hot_start.verbose_description": "Her seviyenin başında kombonuz +30 puanla başlayacak, ancak daha sonra her saniye bir puan düşecek. Etki diğer avantajlarla birikiyor.",
|
||||
"upgrades.hypnosis.name": "Hipnoz",
|
||||
"upgrades.hypnosis.tooltip": "Bir tuğlanın rengi değiştiğinde, o parayı en yakın topa ışınlayın ve tuğlayı lekeleme yeteneğini yeniden yükleyin.",
|
||||
"upgrades.hypnosis.verbose_description": "",
|
||||
"upgrades.implosions.name": "İç patlamalar",
|
||||
"upgrades.implosions.tooltip": "Patlamalar paraları dışarı atmak yerine içeri çekiyor",
|
||||
"upgrades.implosions.verbose_description": "Patlama kuvveti diğer şekilde uygulanır. Daha ileri seviyeler \"daha büyük patlama\" olarak işlev görür.",
|
||||
"upgrades.instant_upgrade.name": "Anında yükseltme",
|
||||
"upgrades.instant_upgrade.tooltip": "Şimdi +2 yükseltme, oyun sonuna kadar -1 seçim.",
|
||||
"upgrades.instant_upgrade.verbose_description": "Hemen iki yükseltme seçin, böylece birini ücretsiz, diğerini de bu avantajı elde etmek için kullanılanı geri ödeyin. Yükseltmeleri seçmek için her sonraki menüde seçebileceğiniz daha az seçenek olacak.",
|
||||
"upgrades.left_is_lava.name": "Sol taraftan kaçının",
|
||||
"upgrades.left_is_lava.tooltip": "+ Kırılan tuğla başına{{lvl}} kombo. Top ekranın sol tarafına çarparsa kombo sıfırlanır",
|
||||
"upgrades.left_is_lava.verbose_description": "Bir tuğlayı kırdığınızda, kombonuz bir artacak, böylece kırdığınız sonraki tüm tuğlalardan bir jeton daha alacaksınız.\n\nAncak, kombonuz topunuz sol tarafa çarptığı anda sıfırlanacaktır. \n\nKombonuz yükseldiği anda, sol taraf kırmızıya dönerek onlara çarpmamanız gerektiğini hatırlatır.\n",
|
||||
"upgrades.limitless.name": "Sınırsız",
|
||||
"upgrades.limitless.tooltip": "Tüm yükseltmelerin maksimum seviyesini {{lvl}} kadar artırın",
|
||||
"upgrades.limitless.verbose_description": "Bu yeteneği seçmek, onun kendi sınırını da bir arttırır ve tekrar seçmenize olanak tanır.",
|
||||
"upgrades.metamorphosis.name": "Başkalaşım",
|
||||
"upgrades.metamorphosis.tooltip": "Her madeni para, {{lvl}} tuğlayı kendi rengiyle lekeleyebilir",
|
||||
"upgrades.metamorphosis.verbose_description": "Bu yetenekle, madeni paralar geldikleri tuğlanın renginde olacak ve dokundukları ilk tuğlayı aynı renge boyayacak. Madeni paralar onları kıran topun hızıyla ortaya çıkar, bu da \"boyamak\" istediğiniz tuğlalara doğru biraz nişan alabileceğiniz anlamına gelir. 1. seviyede, her madeni para \"harcanmadan\" ve içi boş görünmeden önce 1 tuğlayı boyayabilir.",
|
||||
"upgrades.minefield.name": "Mayın tarlası",
|
||||
"upgrades.minefield.tooltip": "Ekrandaki bomba tuğlası başına +{{lvl}} kombo",
|
||||
"upgrades.minefield.verbose_description": "Bir tuğla yerleştirildiğinde komboya +lvl ekler, tuğla yok edildiğinde -lvl ekler ve temel komboyu tuğla sayısıyla lvl çarpımı kadar yükseltir",
|
||||
"upgrades.multiball.name": "Çoklu top",
|
||||
"upgrades.multiball.tooltip": "Her seviyeye {{count}} topla başlayın.",
|
||||
"upgrades.multiball.verbose_description": "Breakout 71'de topu düşürdüğünüz anda kaybedersiniz. \n\nBu avantajla iki top elde edersiniz ve bu yüzden birini kaybetmeyi göze alabilirsiniz. \n\nKaybedilen toplar bir sonraki seviyede geri gelir. \n\nBirden fazla topa sahip olmak bazı ek avantajları kullanılabilir hale getirir ve tabii ki seviyeyi daha hızlı temizler.",
|
||||
"upgrades.nbricks.name": "Sıkı örneklem büyüklüğü",
|
||||
"upgrades.nbricks.tooltip": "Kürek sıçraması başına tam olarak {{lvl}} tuğla vurun +{{lvl}} kombo için, aksi takdirde sıfırlanır",
|
||||
"upgrades.nbricks.verbose_description": "Bu tuğlaları yok etmeniz gerekmiyor ancak onlara vurmanız gerekiyor. Patlamalarla yok edilen tuğlalar sayılmaz",
|
||||
"upgrades.one_more_choice.name": "Ekstra seçenek",
|
||||
"upgrades.one_more_choice.tooltip": "Daha fazla seviye atlama, listede {{lvl}} daha fazla seçenek sunacak",
|
||||
"upgrades.one_more_choice.verbose_description": "Her yükseltme menüsü bir seçeneğe daha sahip olacak. Seçebileceğiniz yükseltme sayısını artırmaz.",
|
||||
"upgrades.ottawa_treaty.name": "Ottawa antlaşması",
|
||||
"upgrades.ottawa_treaty.tooltip": "Bir bombanın yakınında tuğla kırmak onu etkisiz hale getirir",
|
||||
"upgrades.ottawa_treaty.verbose_description": "Yakındaki bomba renkli bir blokla değiştirilecektir. Eğer sapper'ınız varsa, top bir sonraki sıçramaya kadar sapper etkisini kaybedecektir. Aynı anda yalnızca bir bomba değiştirilebilir.",
|
||||
"upgrades.passive_income.name": "Pasif gelir",
|
||||
"upgrades.passive_income.tooltip": "+{{lvl}} kombo / tuğla, kürek önemsizdir {{time}}saniye hareket ettikten sonra",
|
||||
"upgrades.passive_income.verbose_description": "Bazı özellikler, topların hiçbir şey yapmanıza gerek kalmadan istediğinizi yapmasına yardımcı olabilir.",
|
||||
"upgrades.picky_eater.name": "Seçici yiyen",
|
||||
"upgrades.picky_eater.tooltip": "+{{lvl}} kombo her tuğla kırıldığında, top rengi değiştiğinde sıfırlanır",
|
||||
"upgrades.picky_eater.verbose_description": "Topunuzla aynı renkte bir tuğlayı kırdığınızda, kombonuz bir artar. \nEğer farklı bir renkteyse, top yeni rengi alır, ancak kombo sıfırlanır, tabii topun renginde tuğla kalmamışsa. \nMinimumunuzdan daha yüksek bir kombo elde ettiğinizde, yanlış renkteki tuğlalar kırmızı bir kenarlık alır. \nBirden fazla topunuz varsa, bunlardan biri bir tuğlaya çarptığında hepsi renk değiştirir.",
|
||||
"upgrades.pierce.name": "Delme",
|
||||
"upgrades.pierce.tooltip": "Kürek zıplamasından sonra top {{count}} tuğlayı deldi",
|
||||
"upgrades.pierce.verbose_description": "Top normalde bir şeye dokunduğu anda zıplar. Bu avantajla, 3 tuğla kırılıncaya kadar yörüngesine devam eder. \n\nBundan sonra, 4. tuğlada zıplar ve sayacı sıfırlamak için küreğe dokunmanız gerekir.",
|
||||
"upgrades.pierce_color.name": "Renk delme",
|
||||
"upgrades.pierce_color.tooltip": "+{{lvl}} topun rengindeki tuğlalara hasar",
|
||||
"upgrades.pierce_color.verbose_description": "Bir top aynı renkteki bir tuğlaya çarptığında, engellenmeden geçecektir. \n\nFarklı renkteki bir tuğlaya ulaştığında, onu kıracak, rengini alacak ve sekecektir.\n\nSağlam tuğlalarınız varsa, top yine de aynı renkteki bir tuğladan sekebilir.",
|
||||
"upgrades.puck_repulse_ball.help_plural": "Daha güçlü itme kuvveti",
|
||||
"upgrades.puck_repulse_ball.name": "Yumuşak iniş",
|
||||
"upgrades.puck_repulse_ball.tooltip": "Kürek topları iter",
|
||||
"upgrades.puck_repulse_ball.verbose_description": "Bir top küreğe yaklaştığında yavaşlamaya başlayacak ve hatta küreğe değmeden bile zıplamaya başlayacaktır.",
|
||||
"upgrades.rainbow.name": "Gökkuşağı",
|
||||
"upgrades.rainbow.tooltip": "Paralar gökkuşağı renklerinde ortaya çıkar.",
|
||||
"upgrades.rainbow.verbose_description": "Her seviye renkli jetonların oranını artırır. Renk seviye zamanına bağlıdır.",
|
||||
"upgrades.reach.name": "Yukarıdan aşağıya",
|
||||
"upgrades.reach.tooltip": "En alt sıradaki N tuğlasına dokunmak komboyu sıfırlar. Aksi takdirde, +N kombo",
|
||||
"upgrades.reach.verbose_description": "Eğer sadece bir sıra tuğla varsa veya en alttaki tuğla sırası oyunun tüm genişliğini kaplıyorsa, bu avantaj hiçbir işe yaramaz. Aksi takdirde, bu en alttaki sırayı kırmak komboyu sıfırlarken, başka bir şeyi kırmak komboyu o en alttaki sırada bulunan tuğla sayısı kadar artırır. \n\nEn alttaki sıra kırmızıyla vurgulanacaktır.",
|
||||
"upgrades.respawn.name": "Yeniden canlanma",
|
||||
"upgrades.respawn.tooltip": " {{delay}}saniye sonra tuğlaların %{{percent}}'ı yeniden ortaya çıkar.",
|
||||
"upgrades.respawn.verbose_description": "Bazı parçacık efektleri tuğlaların nerede belireceğini size bildirecektir.",
|
||||
"upgrades.right_is_lava.name": "Sağ taraftan kaçının",
|
||||
"upgrades.right_is_lava.tooltip": "Tuğla başına +{{lvl}} kombo. Top ekranın sağ tarafına çarparsa kombo sıfırlanır",
|
||||
"upgrades.right_is_lava.verbose_description": "Bir tuğlayı kırdığınızda, kombonuz bir artacak, böylece kırdığınız sonraki tüm tuğlalardan bir jeton daha alacaksınız.\n\nAncak, topunuz sağ tarafa çarptığı anda kombonuz sıfırlanacaktır.\n\nKombonuz yükseldiği anda, onlara çarpmaktan kaçınmanız gerektiğini hatırlatmak için sağ taraf kırmızı olur.",
|
||||
"upgrades.sacrifice.help_l1": "Bir canı kaybetmek tüm tuğlaları temizler",
|
||||
"upgrades.sacrifice.help_over": "Komboya {{lvl}}can eklendiğinde tüm tuğlalar temizlenir",
|
||||
"upgrades.sacrifice.name": "Kurban etmek",
|
||||
"upgrades.sacrifice.verbose_description": "Bu, komboyu oldukça yükseğe çıkarabilir.",
|
||||
"upgrades.sapper.help_plural": "İlk kırılan {{lvl}} tuğla bombaya dönüşür.",
|
||||
"upgrades.sapper.name": "Kazmacı",
|
||||
"upgrades.sapper.tooltip": "İlk kırılan tuğla bombaya dönüşür.",
|
||||
"upgrades.sapper.verbose_description": "Sadece ortadan kaybolmak yerine, kırdığınız ilk tuğla bir bomba tuğlasıyla değiştirilecektir. Kürek üzerinde topu sektirmek, efekti yeniden etkinleştirir. Bu yeteneği seviyelendirmek, daha fazla bomba yerleştirmenize olanak tanır.",
|
||||
"upgrades.shocks.name": "Şoklar",
|
||||
"upgrades.shocks.tooltip": "Patlayıcı top çarpışmaları",
|
||||
"upgrades.shocks.verbose_description": "İki top çarpıştığında hızları değişir, bir patlama meydana gelir ve onları ayırmak için ek hız kazanırlar.",
|
||||
"upgrades.shunt.name": "Şant",
|
||||
"upgrades.shunt.tooltip": "Kombonuzun {{percent}}%'sini seviyeler arasında tutun",
|
||||
"upgrades.shunt.verbose_description": "Eğer sıcak başlatma özelliğiniz de varsa, sıcak başlatma özelliği mevcut kombinasyona eklenir",
|
||||
"upgrades.side_flip.name": "Sağ elini kullanan",
|
||||
"upgrades.side_flip.tooltip": "Sağdan kırılan tuğla başına +{{lvl}} kombo, aksi takdirde -{{loss}} ",
|
||||
"upgrades.side_flip.verbose_description": "Bir kombo kazanmak için tuğlanın sağ tarafına vurun, ancak sol tarafına vurmaktan kaçının çünkü bu 2 komboyu kaldırır. Üstten ve alttan vurmanın bir etkisi yoktur.",
|
||||
"upgrades.side_kick.name": "Solak",
|
||||
"upgrades.side_kick.tooltip": "Soldan kırılan tuğla başına +{{lvl}} kombo, aksi takdirde -{{loss}} ",
|
||||
"upgrades.side_kick.verbose_description": "Tuğlanın sol tarafına vurarak bir kombo elde edin, ancak sağ tarafına vurmaktan kaçının çünkü bu 2 komboyu kaldırır. Üstten ve alttan vurmanın bir etkisi yoktur.",
|
||||
"upgrades.skip_last.help_plural": "Son {{lvl}} tuğla patlayacak.",
|
||||
"upgrades.skip_last.name": "Kolay Temizlik",
|
||||
"upgrades.skip_last.tooltip": "Son tuğla patlayacak.",
|
||||
"upgrades.skip_last.verbose_description": "Bir sonraki seviyeye geçmek için tüm tuğlaları kırmanız gerekir. Ancak son tuğlaları elde etmek zor olabilir. \n\nBir seviyeyi erken bitirmek, yükseltme sırasında ekstra seçenekler sunar. Tuğlaları asla kaçırmamak da çok faydalıdır. \n\nYani son tuğlaları kırmakta zorlanıyorsanız, bu yeteneği birkaç kez elde etmek yardımcı olabilir.",
|
||||
"upgrades.slow_down.name": "Daha yavaş top",
|
||||
"upgrades.slow_down.tooltip": "Top daha yavaş hareket ediyor",
|
||||
"upgrades.slow_down.verbose_description": "Top nispeten yavaş başlar, ancak oyununuzun her seviyesinde biraz daha hızlı başlayacaktır. \n\nAyrıca bir seviyede çok zaman geçirirseniz hızlanacaktır. \n\nBu avantaj onu daha yönetilebilir hale getirir. \n\nMenüde çocuk modunu etkinleştirerek her seferinde başlangıçta alabilirsiniz.",
|
||||
"upgrades.smaller_puck.name": "Daha küçük kürek",
|
||||
"upgrades.smaller_puck.tooltip": "Ayrıca +{{percent}}% jeton verir",
|
||||
"upgrades.smaller_puck.verbose_description": "Bu, küreği daha küçük hale getirir, bu da teoride bazı köşe vuruşlarını kolaylaştırır, ancak gerçekte sadece zorluğu artırır.\n\nBu yüzden ayrıca +%50 jeton yumurtlama bonusu da alırsınız.",
|
||||
"upgrades.soft_reset.name": "Yumuşak sıfırlama",
|
||||
"upgrades.soft_reset.tooltip": "Kombo sıfırlamaları % {{percent}}tutar",
|
||||
"upgrades.soft_reset.verbose_description": "Bir kombo sıfırlamanın etkisini sınırlayın.",
|
||||
"upgrades.sticky_coins.name": "Yapışkan paralar",
|
||||
"upgrades.sticky_coins.tooltip": "",
|
||||
"upgrades.sticky_coins.verbose_description": "",
|
||||
"upgrades.streak_shots.name": "Vuruş serisi",
|
||||
"upgrades.streak_shots.tooltip": "Kürek çekmeden önce çok sayıda tuğla kırarsanız daha fazla para kazanırsınız.",
|
||||
"upgrades.streak_shots.verbose_description": "Her tuğlayı kırdığınızda, kombonuz bir artar. \n\nAncak, top küreğinize değdiği anda kombo varsayılan değerine sıfırlanır.\n\nKombonuz temel değerin üzerine çıktığında, küreğinizin topla dokunduğunuzda kombonuzu yok edeceğini size hatırlatmak için kırmızı bir kenarı olacaktır.",
|
||||
"upgrades.sturdy_bricks.name": "Sağlam tuğlalar",
|
||||
"upgrades.sturdy_bricks.tooltip": "+{{lvl}} tuğla HP, kırıldığında ortaya çıkan +{{percent}}% para",
|
||||
"upgrades.sturdy_bricks.verbose_description": "Bu yeteneğin her seviyesi tüm tuğlalara bir HP ekler. HP sayısını \"clairvoyant\" yeteneğiyle görebilirsiniz. \"Piercing\" yeteneğini alarak top hasarını artırabilirsiniz. Yeteneğin her seviyesi +50% jeton spawn'ı ekler.",
|
||||
"upgrades.superhot.name": "SÜPER SICAK",
|
||||
"upgrades.superhot.tooltip": "Kürek hareket ettikçe zaman da hareket eder.",
|
||||
"upgrades.superhot.verbose_description": "SÜPER SICAK SÜPER SICAK SÜPER SICAK SÜPER SICAK",
|
||||
"upgrades.telekinesis.help_plural": "Top üzerinde daha güçlü etki",
|
||||
"upgrades.telekinesis.name": "Telekinezi",
|
||||
"upgrades.telekinesis.tooltip": "Kürek topun yörüngesini kontrol eder",
|
||||
"upgrades.telekinesis.verbose_description": "Top yukarı doğru giderken onu kontrol ediyorsun.",
|
||||
"upgrades.three_cushion.name": "Üç yastık",
|
||||
"upgrades.three_cushion.tooltip": "Yanlarda ve üstte her vuruşta +1 kombo, kürek sıçraması başına +{{max}} 'a kadar. Önce sıçramadan bir tuğlaya çarptığınızda kombo sıfırlanır.",
|
||||
"upgrades.three_cushion.verbose_description": "Bir tarafa yapılan her vuruş komboyu bir, +3'e kadar yükseltir. Bundan sonra, bir sonraki kürek sıçramasına kadar kombo kazanılmaz.",
|
||||
"upgrades.top_is_lava.name": "Sınır gökyüzüdür",
|
||||
"upgrades.top_is_lava.tooltip": "Tuğla başına +{{lvl}} kombo, tepeye vurulduğunda sıfırlanır",
|
||||
"upgrades.top_is_lava.verbose_description": "Bir tuğlayı kırdığınızda, kombonuz bir artar. Ancak, topunuz ekranın tepesine çarptığı anda kombonuz sıfırlanır. \n\nKombonuz minimumun üzerinde olduğunda, ona çarpmamanız gerektiğini hatırlatmak için üstte kırmızı bir çubuk belirir.",
|
||||
"upgrades.trampoline.name": "Trambolin",
|
||||
"upgrades.trampoline.tooltip": "+ kürek sıçraması başına{{lvl}} kombo,- herhangi bir sınırda sıçrama başına{{lvl}} kombo",
|
||||
"upgrades.trampoline.verbose_description": "Sıfırlama koşulu eklemeyen nadir kombo yükseltmelerinden biri",
|
||||
"upgrades.transparency.name": "Şeffaflık",
|
||||
"upgrades.transparency.tooltip": "Top ekranın üst kısmında şeffaf hale gelir. Tüm toplar tam şeffaflığa ulaştığında +{{percent}} % jeton",
|
||||
"upgrades.transparency.verbose_description": "Daha yüksek seviyeler topun daha çabuk şeffaf olmasını sağlar ve puan bonusunu artırır.",
|
||||
"upgrades.trickledown.name": "Sızma ekonomisi",
|
||||
"upgrades.trickledown.tooltip": "Paralar ekranın üst kısmında görünür.",
|
||||
"upgrades.trickledown.verbose_description": "Kenara biraz para ayırmanıza yardımcı olabilir.",
|
||||
"upgrades.unbounded.name": "Dolgu",
|
||||
"upgrades.unbounded.tooltip": "Seviyenin sağına ve soluna boşluk ekler, ancak küreğiniz o kadar uzağa gidemez.",
|
||||
"upgrades.unbounded.verbose_description": "Bir diğer geliştirme ise küreğinizin erişim mesafesini uzatmanıza yardımcı olabilir.",
|
||||
"upgrades.viscosity.name": "Viskozite",
|
||||
"upgrades.viscosity.tooltip": "Daha yavaş para düşüşü",
|
||||
"upgrades.viscosity.verbose_description": "Madeni paralar normalde yer çekimi ve patlamalarla oldukça yüksek hızlara ulaşır. \n\nBu yetenek, sanki bir tür viskoz sıvının içindeymiş gibi sürekli olarak yavaşlamalarını sağlar. \n\nBu, onları yakalamayı kolaylaştırır ve madeni paranın hareketini etkileyen yeteneklerle güzel bir şekilde birleşir.",
|
||||
"upgrades.wind.help_plural": "Daha güçlü rüzgar kuvveti",
|
||||
"upgrades.wind.name": "Rüzgâr",
|
||||
"upgrades.wind.tooltip": "Kürek pozisyonu rüzgar yaratır",
|
||||
"upgrades.wind.verbose_description": "Rüzgar küreğin pozisyonuna bağlıdır: sol sola eser, sağ sağa eser. Hem topları hem de paraları etkiler.",
|
||||
"upgrades.wrap_left.name": "",
|
||||
"upgrades.wrap_left.tooltip": "",
|
||||
"upgrades.wrap_left.verbose_description": "",
|
||||
"upgrades.wrap_right.name": "",
|
||||
"upgrades.wrap_right.tooltip": "",
|
||||
"upgrades.wrap_right.verbose_description": "",
|
||||
"upgrades.yoyo.name": "Yo-yo",
|
||||
"upgrades.yoyo.tooltip": "Top küreğe doğru düşer",
|
||||
"upgrades.yoyo.verbose_description": "Telekinezinin tam tersi, topun aşağı düşerken kontrol edilmesi.",
|
||||
"upgrades.zen.name": "Zen",
|
||||
"upgrades.zen.tooltip": "",
|
||||
"upgrades.zen.verbose_description": ""
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
<body>
|
||||
<button id="menu">☰ <span id="menuLabel">menu</span></button>
|
||||
<button id="score"></button>
|
||||
<div id="stats" style="display: none"></div>
|
||||
|
||||
<canvas id="game"></canvas>
|
||||
<div id="popup">
|
||||
|
|
297
src/levelEditor.ts
Normal file
297
src/levelEditor.ts
Normal file
|
@ -0,0 +1,297 @@
|
|||
import { icons, transformRawLevel } from "./loadGameData";
|
||||
import { t } from "./i18n/i18n";
|
||||
import { getSettingValue, getTotalScore, setSettingValue } from "./settings";
|
||||
import { asyncAlert } from "./asyncAlert";
|
||||
import { Palette, RawLevel } from "./types";
|
||||
import { levelIconHTML } from "./levelIcon";
|
||||
|
||||
import _palette from "./data/palette.json";
|
||||
import { restart } from "./game";
|
||||
import { describeLevel } from "./game_utils";
|
||||
|
||||
const palette = _palette as Palette;
|
||||
const MAX_LEVEL_SIZE = 21;
|
||||
const MIN_LEVEL_SIZE = 2;
|
||||
|
||||
export function levelEditorMenuEntry() {
|
||||
const min = 10000;
|
||||
const disabled = getTotalScore() < min;
|
||||
return {
|
||||
icon: icons["icon:editor"],
|
||||
text: t("editor.title"),
|
||||
disabled,
|
||||
help: disabled ? t("editor.locked", { min }) : t("editor.help"),
|
||||
async value() {
|
||||
openLevelEditorLevelsList().then();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function openLevelEditorLevelsList() {
|
||||
const rawList = getSettingValue("custom_levels", []) as RawLevel[];
|
||||
const customLevels = rawList.map(transformRawLevel);
|
||||
|
||||
let choice = await asyncAlert({
|
||||
title: t("editor.title"),
|
||||
content: [
|
||||
...customLevels.map((l, li) => ({
|
||||
text: l.name,
|
||||
icon: levelIconHTML(l.bricks, l.size, l.color),
|
||||
value() {
|
||||
editRawLevelList(li);
|
||||
},
|
||||
help: l.credit || describeLevel(l),
|
||||
})),
|
||||
{
|
||||
text: t("editor.new_level"),
|
||||
icon: icons["icon:editor"],
|
||||
value() {
|
||||
rawList.push({
|
||||
color: "",
|
||||
size: 6,
|
||||
bricks: "____________________________________",
|
||||
name: "custom level" + (rawList.length + 1),
|
||||
credit: "",
|
||||
});
|
||||
setSettingValue("custom_levels", rawList);
|
||||
editRawLevelList(rawList.length - 1);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: t("editor.import"),
|
||||
help: t("editor.import_instruction"),
|
||||
value() {
|
||||
const code = prompt(t("editor.import_instruction"))?.trim();
|
||||
if (code) {
|
||||
let [name, credit] = code.match(/\[([^\]]+)]/gi);
|
||||
|
||||
let bricks = code
|
||||
.split(name)[1]
|
||||
.split(credit)[0]
|
||||
.replace(/\s/gi, "");
|
||||
name = name.slice(1, -1);
|
||||
credit = credit.slice(1, -1);
|
||||
name ||= "Imported on " + new Date().toISOString().slice(0, 10);
|
||||
credit ||= "";
|
||||
const size = Math.sqrt(bricks.length);
|
||||
if (
|
||||
Math.floor(size) === size &&
|
||||
size >= MIN_LEVEL_SIZE &&
|
||||
size <= MAX_LEVEL_SIZE
|
||||
) {
|
||||
rawList.push({
|
||||
color: automaticBackgroundColor(bricks.split("")),
|
||||
size,
|
||||
bricks,
|
||||
name,
|
||||
credit,
|
||||
});
|
||||
setSettingValue("custom_levels", rawList);
|
||||
}
|
||||
}
|
||||
openLevelEditorLevelsList();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
if (typeof choice == "function") choice();
|
||||
}
|
||||
|
||||
export async function editRawLevelList(nth: number, color = "W") {
|
||||
let rawList = getSettingValue("custom_levels", []) as RawLevel[];
|
||||
const level = rawList[nth];
|
||||
const bricks = level.bricks.split("");
|
||||
let grid = "";
|
||||
for (let y = 0; y < level.size; y++) {
|
||||
grid += '<div style="background: ' + (level.color || "black") + ';">';
|
||||
for (let x = 0; x < level.size; x++) {
|
||||
const c = bricks[y * level.size + x];
|
||||
grid += `<span data-resolve-to="paint_brick:${x}:${y}" style="background: ${palette[c]}">${c == "B" ? "💣" : ""}</span>`;
|
||||
}
|
||||
grid += "</div>";
|
||||
}
|
||||
|
||||
const levelColors = new Set(bricks);
|
||||
levelColors.delete("_");
|
||||
levelColors.delete("B");
|
||||
|
||||
let colorList =
|
||||
'<div class="palette">' +
|
||||
Object.entries(palette)
|
||||
.filter(([key, value]) => key !== "_")
|
||||
.filter(
|
||||
([key, value]) =>
|
||||
levelColors.size < 5 || levelColors.has(key) || key === "B",
|
||||
)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`<span data-resolve-to="set_color:${key}" data-selected="${key == color}" style="background: ${value}">${key == "B" ? "💣" : ""}</span>`,
|
||||
)
|
||||
.join("") +
|
||||
"</div>";
|
||||
|
||||
const clicked = await asyncAlert<string | null>({
|
||||
title: t("editor.editing.title", { name: level.name }),
|
||||
content: [
|
||||
t("editor.editing.color"),
|
||||
colorList,
|
||||
t("editor.editing.help"),
|
||||
`<div class="gridEdit" style="--grid-size:${level.size};">${grid}</div>`,
|
||||
|
||||
{
|
||||
icon: icons["icon:new_run"],
|
||||
text: t("editor.editing.play"),
|
||||
value: "play",
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.rename"),
|
||||
value: "rename",
|
||||
help: level.name,
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.credit"),
|
||||
value: "credit",
|
||||
help: level.credit,
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.delete"),
|
||||
value: "delete",
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.copy"),
|
||||
value: "copy",
|
||||
help: t("editor.editing.copy_help"),
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.bigger"),
|
||||
value: "size:+1",
|
||||
disabled: level.size >= MAX_LEVEL_SIZE,
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.smaller"),
|
||||
value: "size:-1",
|
||||
disabled: level.size <= MIN_LEVEL_SIZE,
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.left"),
|
||||
value: "move:-1:0",
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.right"),
|
||||
value: "move:1:0",
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.up"),
|
||||
value: "move:0:-1",
|
||||
},
|
||||
{
|
||||
text: t("editor.editing.down"),
|
||||
value: "move:0:1",
|
||||
},
|
||||
],
|
||||
});
|
||||
if (!clicked) return;
|
||||
if (typeof clicked === "string") {
|
||||
const [action, a, b] = clicked.split(":");
|
||||
if (action == "paint_brick") {
|
||||
const x = parseInt(a),
|
||||
y = parseInt(b);
|
||||
bricks[y * level.size + x] =
|
||||
bricks[y * level.size + x] === color ? "_" : color;
|
||||
level.bricks = bricks.join("");
|
||||
}
|
||||
if (action == "set_color") {
|
||||
color = a;
|
||||
}
|
||||
if (action == "size") {
|
||||
const newSize = level.size + parseInt(a);
|
||||
const newBricks = [];
|
||||
for (let y = 0; y < newSize; y++) {
|
||||
for (let x = 0; x < newSize; x++) {
|
||||
newBricks.push(
|
||||
(x < level.size && y < level.size && bricks[y * level.size + x]) ||
|
||||
"_",
|
||||
);
|
||||
}
|
||||
}
|
||||
level.size = newSize;
|
||||
level.bricks = newBricks.join("");
|
||||
}
|
||||
if (action == "move") {
|
||||
const dx = parseInt(a),
|
||||
dy = parseInt(b);
|
||||
const newBricks = [];
|
||||
for (let y = 0; y < level.size; y++) {
|
||||
for (let x = 0; x < level.size; x++) {
|
||||
const tx = x - dx;
|
||||
const ty = y - dy;
|
||||
if (tx < 0 || tx >= level.size || ty < 0 || ty >= level.size) {
|
||||
newBricks.push("_");
|
||||
} else {
|
||||
newBricks.push(bricks[ty * level.size + tx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
level.bricks = newBricks.join("");
|
||||
}
|
||||
if (action === "play") {
|
||||
restart({
|
||||
level: transformRawLevel(level),
|
||||
isEditorTrialRun: nth,
|
||||
perks: {
|
||||
base_combo: 7,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (action === "copy") {
|
||||
let text =
|
||||
"```\n[" +
|
||||
(level.name || "unnamed level")?.replace(/\[|\]/gi, " ") +
|
||||
"]";
|
||||
bricks.forEach((b, bi) => {
|
||||
if (!(bi % level.size)) text += "\n";
|
||||
text += b;
|
||||
});
|
||||
text +=
|
||||
"\n[" +
|
||||
(level.credit?.replace(/\[|\]/gi, " ") || "Missing credits") +
|
||||
"]\n```";
|
||||
navigator.clipboard.writeText(text);
|
||||
// return
|
||||
}
|
||||
if (action === "rename") {
|
||||
const name = prompt(t("editor.editing.rename_prompt"), level.name);
|
||||
if (name) {
|
||||
level.name = name;
|
||||
}
|
||||
}
|
||||
if (action === "credit") {
|
||||
const credit = prompt(
|
||||
t("editor.editing.credit_prompt"),
|
||||
level.credit || "",
|
||||
);
|
||||
if (credit !== "null") {
|
||||
level.credit = credit || "";
|
||||
}
|
||||
}
|
||||
if (action === "delete") {
|
||||
rawList = rawList.filter((l, li) => li !== nth);
|
||||
setSettingValue("custom_levels", rawList);
|
||||
openLevelEditorLevelsList();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
level.color = automaticBackgroundColor(bricks);
|
||||
|
||||
setSettingValue("custom_levels", rawList);
|
||||
editRawLevelList(nth, color);
|
||||
}
|
||||
|
||||
function automaticBackgroundColor(bricks: string[]) {
|
||||
return bricks.filter((b) => b === "g").length >
|
||||
bricks.filter((b) => b !== "_").length * 0.05
|
||||
? "#115988"
|
||||
: "";
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import _palette from "./data/palette.json";
|
||||
import _rawLevelsList from "./data/levels.json";
|
||||
import _appVersion from "./data/version.json";
|
||||
import { rawUpgrades } from "./upgrades";
|
||||
|
||||
describe("json data checks", () => {
|
||||
it("_rawLevelsList has icon levels", () => {
|
||||
|
@ -10,13 +9,6 @@ describe("json data checks", () => {
|
|||
).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
it("all upgrades have icons", () => {
|
||||
const missingIcon = rawUpgrades.filter(
|
||||
(u) => !_rawLevelsList.find((l) => l.name == "icon:" + u.id),
|
||||
);
|
||||
expect(missingIcon).toEqual([]);
|
||||
});
|
||||
|
||||
it("_rawLevelsList has non-icon few levels", () => {
|
||||
expect(
|
||||
_rawLevelsList.filter((l) => !l.name.startsWith("icon:")).length,
|
||||
|
@ -28,7 +20,7 @@ describe("json data checks", () => {
|
|||
.filter((l) => {
|
||||
const uniqueBricks = l.bricks
|
||||
.split("")
|
||||
.filter((b) => b !== "_" && b !== "black")
|
||||
.filter((b) => b !== "_" && b !== "B")
|
||||
.filter((a, b, c) => c.indexOf(a) === b);
|
||||
return uniqueBricks.length > 5 && !l.name.startsWith("icon:");
|
||||
})
|
||||
|
|
|
@ -13,28 +13,29 @@ const rawLevelsList = _rawLevelsList as RawLevel[];
|
|||
export const appVersion = _appVersion as string;
|
||||
|
||||
export const icons = {} as { [k: string]: string };
|
||||
export const allLevelsAndIcons = rawLevelsList
|
||||
.map((level, i) => {
|
||||
const bricks = level.bricks
|
||||
.split("")
|
||||
.map((c) => palette[c])
|
||||
.slice(0, level.size * level.size);
|
||||
const bricksCount = bricks.filter((i) => i).length;
|
||||
const icon = levelIconHTML(bricks, level.size, level.color);
|
||||
icons[level.name] = icon;
|
||||
return {
|
||||
...level,
|
||||
bricks,
|
||||
bricksCount,
|
||||
icon,
|
||||
color: level.color || "#000000",
|
||||
svg: getLevelBackground(level),
|
||||
};
|
||||
})
|
||||
.map((l, li) => ({
|
||||
...l,
|
||||
sortKey: ((Math.random() + 3) / 3.5) * l.bricksCount,
|
||||
})) as Level[];
|
||||
|
||||
export function transformRawLevel(level: RawLevel) {
|
||||
const bricks = level.bricks
|
||||
.split("")
|
||||
.map((c) => palette[c])
|
||||
.slice(0, level.size * level.size);
|
||||
const bricksCount = bricks.filter((i) => i).length;
|
||||
const icon = levelIconHTML(bricks, level.size, level.color);
|
||||
icons[level.name] = icon;
|
||||
return {
|
||||
...level,
|
||||
bricks,
|
||||
bricksCount,
|
||||
icon,
|
||||
color: level.color || "#000000",
|
||||
svg: getLevelBackground(level),
|
||||
sortKey: ((Math.random() + 3) / 3.5) * bricksCount,
|
||||
};
|
||||
}
|
||||
|
||||
export const allLevelsAndIcons = rawLevelsList.map(
|
||||
transformRawLevel,
|
||||
) as Level[];
|
||||
|
||||
export const allLevels = allLevelsAndIcons.filter(
|
||||
(l) => !l.name.startsWith("icon:"),
|
||||
|
|
|
@ -4,6 +4,7 @@ import _appVersion from "./data/version.json";
|
|||
import { generateSaveFileContent } from "./generateSaveFileContent";
|
||||
import { getLevelUnlockCondition, reasonLevelIsLocked } from "./game_utils";
|
||||
import { allLevels } from "./loadGameData";
|
||||
import { toast } from "./toast";
|
||||
|
||||
// The page will be reloaded if any migrations were run
|
||||
let migrationsRun = 0;
|
||||
|
@ -15,6 +16,7 @@ function migrate(name: string, cb: () => void) {
|
|||
localStorage.setItem(name, "" + Date.now());
|
||||
migrationsRun++;
|
||||
} catch (e) {
|
||||
toast((e as Error).message);
|
||||
console.warn("Migration " + name + " failed : ", e);
|
||||
}
|
||||
}
|
||||
|
@ -80,16 +82,28 @@ migrate("remove_long_and_creative_mode_data", () => {
|
|||
localStorage.setItem("breakout_71_runs_history", JSON.stringify(cleaned));
|
||||
});
|
||||
|
||||
migrate("compact_runs_data", () => {
|
||||
migrate("compact_runs_data_again", () => {
|
||||
let runsHistory = JSON.parse(
|
||||
localStorage.getItem("breakout_71_runs_history") || "[]",
|
||||
) as RunHistoryItem[];
|
||||
runsHistory = runsHistory.filter((r) => {
|
||||
if (!r.perks) return false;
|
||||
if ("mode" in r) {
|
||||
if (r.mode !== "short") {
|
||||
return false;
|
||||
}
|
||||
delete r.mode;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
runsHistory.forEach((r) => {
|
||||
r.runTime = Math.round(r.runTime);
|
||||
for (let key in r.perks) {
|
||||
if (r.perks && !r.perks[key]) {
|
||||
delete r.perks[key];
|
||||
if (r.perks) {
|
||||
for (let key in r.perks) {
|
||||
if (!r.perks[key]) {
|
||||
delete r.perks[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("best_level_score" in r) {
|
||||
|
@ -126,4 +140,25 @@ migrate("set_breakout_71_unlocked_levels" + _appVersion, () => {
|
|||
);
|
||||
});
|
||||
|
||||
migrate("clean_ls", () => {
|
||||
for (let key in localStorage) {
|
||||
try {
|
||||
JSON.parse(localStorage.getItem(key) || "null");
|
||||
} catch (e) {
|
||||
localStorage.removeItem(key);
|
||||
console.warn("Removed invalid key " + key, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
migrate("set_user_id", () => {
|
||||
// Useful to identify a player when uploading his save file multiple times to a web service
|
||||
if (!localStorage.getItem("breakout_71_user_id")) {
|
||||
localStorage.setItem(
|
||||
"breakout_71_user_id",
|
||||
JSON.stringify(self?.crypto?.randomUUID() || "user_" + Math.random()),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
afterMigration();
|
||||
|
|
|
@ -32,6 +32,9 @@ export function monitorLevelsUnlocks(gameState: GameState) {
|
|||
// Already unlocked
|
||||
if (unlocked.has(name)) return;
|
||||
// Score not reached yet
|
||||
if (gameState.score < minScore) return;
|
||||
if (!minScore) return;
|
||||
|
||||
if (gameState.score < minScore) return;
|
||||
// We are missing a required perk
|
||||
if (required.find((id) => !gameState.perks[id])) return;
|
||||
|
|
|
@ -28,12 +28,12 @@ export function getRunLevels(
|
|||
(l, li) =>
|
||||
unlockedBefore.has(l.name) || !reasonLevelIsLocked(li, history, false),
|
||||
);
|
||||
const firstLevel = allLevelsAndIcons.filter(
|
||||
(l) => l.name == (params?.level || "icon:" + randomGift),
|
||||
);
|
||||
const firstLevel = params?.level
|
||||
? [params.level]
|
||||
: allLevelsAndIcons.filter((l) => l.name == "icon:" + randomGift);
|
||||
|
||||
const restInRandomOrder = unlocked
|
||||
.filter((l) => l.name !== params?.level)
|
||||
.filter((l) => l.name !== params?.level?.name)
|
||||
.filter((l) => l.name !== params?.levelToAvoid)
|
||||
.sort(() => Math.random() - 0.5);
|
||||
|
||||
|
@ -65,6 +65,7 @@ export function newGameState(params: RunParams): GameState {
|
|||
const runLevels = getRunLevels(params, randomGift);
|
||||
|
||||
const gameState: GameState = {
|
||||
startParams: params,
|
||||
runLevels,
|
||||
level: runLevels[0],
|
||||
currentLevel: 0,
|
||||
|
@ -81,6 +82,7 @@ export function newGameState(params: RunParams): GameState {
|
|||
puckPosition: 400,
|
||||
lastPuckPosition: 400,
|
||||
lastPuckMove: 0,
|
||||
lastZenComboIncrease: 0,
|
||||
pauseTimeout: null,
|
||||
canvasWidth: 0,
|
||||
canvasHeight: 0,
|
||||
|
@ -141,8 +143,7 @@ export function newGameState(params: RunParams): GameState {
|
|||
creative:
|
||||
params?.computer_controlled ||
|
||||
sumOfValues(params.perks) > 1 ||
|
||||
(params.level && !params.level.startsWith("icon:")),
|
||||
computer_controlled: params?.computer_controlled || false,
|
||||
(params.level && !params.level.name.startsWith("icon:")),
|
||||
};
|
||||
resetBalls(gameState);
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ import { t } from "./i18n/i18n";
|
|||
|
||||
import { OptionDef, OptionId } from "./types";
|
||||
import { getSettingValue, setSettingValue } from "./settings";
|
||||
import { hoursSpentPlaying } from "./pure_functions";
|
||||
|
||||
import { hoursSpentPlaying } from "./game_utils";
|
||||
|
||||
export const options = {
|
||||
sound: {
|
||||
|
@ -30,6 +31,21 @@ export const options = {
|
|||
name: t("settings.extra_bright"),
|
||||
help: t("settings.extra_bright_help"),
|
||||
},
|
||||
smooth_lighting: {
|
||||
default: true,
|
||||
name: t("settings.smooth_lighting"),
|
||||
help: t("settings.smooth_lighting_help"),
|
||||
},
|
||||
precise_lighting: {
|
||||
default: true,
|
||||
name: t("settings.precise_lighting"),
|
||||
help: t("settings.precise_lighting_help"),
|
||||
},
|
||||
probabilistic_lighting: {
|
||||
default: false,
|
||||
name: t("settings.probabilistic_lighting"),
|
||||
help: t("settings.probabilistic_lighting_help"),
|
||||
},
|
||||
contrast: {
|
||||
default: false,
|
||||
name: t("settings.contrast"),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { Ball, GameState } from "./types";
|
||||
|
||||
export function clamp(value: number, min: number, max: number) {
|
||||
return Math.max(min, Math.min(value, max));
|
||||
}
|
||||
|
@ -6,14 +8,30 @@ export function comboKeepingRate(level: number) {
|
|||
return clamp(1 - (1 / (1 + level)) * 1.5, 0, 1);
|
||||
}
|
||||
|
||||
export function hoursSpentPlaying() {
|
||||
try {
|
||||
const timePlayed =
|
||||
localStorage.getItem("breakout_71_total_play_time") || "0";
|
||||
return Math.floor(parseFloat(timePlayed) / 1000 / 60 / 60);
|
||||
} catch (e) {
|
||||
return 0;
|
||||
export function ballTransparency(ball: Ball, gameState: GameState) {
|
||||
if (!gameState.perks.transparency) return 0;
|
||||
return clamp(
|
||||
gameState.perks.transparency *
|
||||
(1 - (ball.y / gameState.gameZoneHeight) * 1.2),
|
||||
0,
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
export function coinsBoostedCombo(gameState: GameState) {
|
||||
let boost =
|
||||
1 + gameState.perks.sturdy_bricks / 2 + gameState.perks.smaller_puck / 2;
|
||||
if (gameState.perks.transparency) {
|
||||
let min = 1;
|
||||
gameState.balls.forEach((ball) => {
|
||||
const bt = ballTransparency(ball, gameState);
|
||||
if (bt < min) {
|
||||
min = bt;
|
||||
}
|
||||
});
|
||||
boost += (min * gameState.perks.transparency) / 2;
|
||||
}
|
||||
return Math.ceil(Math.max(gameState.combo, gameState.lastCombo) * boost);
|
||||
}
|
||||
|
||||
export function miniMarkDown(md: string) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { gameCanvas } from "./render";
|
||||
import { max_levels } from "./game_utils";
|
||||
import { isInWebView, max_levels } from "./game_utils";
|
||||
import { getAudioRecordingTrack } from "./sounds";
|
||||
import { t } from "./i18n/i18n";
|
||||
import { GameState } from "./types";
|
||||
import { isOptionOn } from "./options";
|
||||
import { toast } from "./toast";
|
||||
|
||||
let mediaRecorder: MediaRecorder | null,
|
||||
captureStream: MediaStream,
|
||||
|
@ -88,6 +89,7 @@ export function startRecordingGame(gameState: GameState) {
|
|||
const recordedChunks: Blob[] = [];
|
||||
|
||||
const instance = new MediaRecorder(captureStream, {
|
||||
// Required for less mushy result
|
||||
videoBitsPerSecond: 3500000,
|
||||
});
|
||||
mediaRecorder = instance;
|
||||
|
@ -107,6 +109,7 @@ export function startRecordingGame(gameState: GameState) {
|
|||
) {
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
}
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.autoplay = true;
|
||||
video.controls = false;
|
||||
|
@ -124,12 +127,12 @@ export function startRecordingGame(gameState: GameState) {
|
|||
const a = document.createElement("a");
|
||||
a.download = captureFileName("webm");
|
||||
a.target = "_blank";
|
||||
if (window.location.href.endsWith("index.html?isInWebView=true")) {
|
||||
|
||||
if (isInWebView) {
|
||||
a.href = await blobToBase64(blob);
|
||||
} else {
|
||||
a.href = video.src;
|
||||
}
|
||||
|
||||
a.textContent = t("settings.record_download", {
|
||||
size: (blob.size / 1000000).toFixed(2),
|
||||
});
|
||||
|
@ -144,8 +147,10 @@ function blobToBase64(blob: Blob): Promise<string> {
|
|||
reader.onload = function () {
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reader.onerror = function () {
|
||||
const e = reader.error;
|
||||
console.error(e);
|
||||
toast(e?.message || "Failed to convert the video to a data url");
|
||||
reject(new Error("Failed to readAsDataURL of the video "));
|
||||
};
|
||||
|
||||
|
|
338
src/render.ts
338
src/render.ts
|
@ -1,9 +1,10 @@
|
|||
import { baseCombo, forEachLiveOne, liveCount } from "./gameStateMutators";
|
||||
import {
|
||||
ballTransparency,
|
||||
brickCenterX,
|
||||
brickCenterY,
|
||||
currentLevelInfo,
|
||||
getCoinRenderColor,
|
||||
getCornerOffset,
|
||||
isMovingWhilePassiveIncome,
|
||||
isPickyEatingPossible,
|
||||
max_levels,
|
||||
|
@ -11,13 +12,15 @@ import {
|
|||
telekinesisEffectRate,
|
||||
yoyoEffectRate,
|
||||
} from "./game_utils";
|
||||
import { Coin, colorString, GameState } from "./types";
|
||||
import { colorString, GameState } from "./types";
|
||||
import { t } from "./i18n/i18n";
|
||||
import { gameState, lastMeasuredFPS } from "./game";
|
||||
import { gameState, lastMeasuredFPS, startWork } from "./game";
|
||||
import { isOptionOn } from "./options";
|
||||
import {
|
||||
ballTransparency,
|
||||
catchRateBest,
|
||||
catchRateGood,
|
||||
coinsBoostedCombo,
|
||||
levelTimeBest,
|
||||
levelTimeGood,
|
||||
missesBest,
|
||||
|
@ -25,6 +28,7 @@ import {
|
|||
wallBouncedBest,
|
||||
wallBouncedGood,
|
||||
} from "./pure_functions";
|
||||
import { getCurrentMaxCoins } from "./settings";
|
||||
|
||||
export const gameCanvas = document.getElementById("game") as HTMLCanvasElement;
|
||||
export const ctx = gameCanvas.getContext("2d", {
|
||||
|
@ -48,9 +52,14 @@ const haloCanvasCtx = haloCanvas.getContext("2d", {
|
|||
alpha: false,
|
||||
}) as CanvasRenderingContext2D;
|
||||
|
||||
export const haloScale = 16;
|
||||
export function getHaloScale() {
|
||||
return 16 * (isOptionOn("precise_lighting") ? 1 : 2);
|
||||
}
|
||||
|
||||
let framesCounter = 0;
|
||||
export function render(gameState: GameState) {
|
||||
framesCounter++;
|
||||
startWork("render:init");
|
||||
const level = currentLevelInfo(gameState);
|
||||
|
||||
const hasCombo = gameState.combo > baseCombo(gameState);
|
||||
|
@ -67,17 +76,18 @@ export function render(gameState: GameState) {
|
|||
}
|
||||
|
||||
const catchRate = gameState.levelSpawnedCoins
|
||||
? (gameState.levelSpawnedCoins - gameState.levelLostCoins) /
|
||||
gameState.levelSpawnedCoins
|
||||
: 1;
|
||||
|
||||
? (gameState.score - gameState.levelStartScore) /
|
||||
(gameState.levelSpawnedCoins || 1)
|
||||
: // (gameState.levelSpawnedCoins - gameState.levelLostCoins) /
|
||||
// gameState.levelSpawnedCoins
|
||||
1;
|
||||
startWork("render:scoreDisplay");
|
||||
scoreDisplay.innerHTML =
|
||||
(isOptionOn("show_fps")
|
||||
(isOptionOn("show_fps") || gameState.startParams.computer_controlled
|
||||
? `
|
||||
<span class="${(Math.abs(lastMeasuredFPS - 60) < 2 && " ") || (Math.abs(lastMeasuredFPS - 60) < 10 && "good") || "bad"}">
|
||||
<span class="${(Math.abs(lastMeasuredFPS - 60) < 2 && " ") || (Math.abs(lastMeasuredFPS - 60) < 10 && "good") || "bad"}">
|
||||
${lastMeasuredFPS} FPS
|
||||
</span><span> / </span>
|
||||
|
||||
`
|
||||
: "") +
|
||||
(isOptionOn("show_stats")
|
||||
|
@ -99,23 +109,33 @@ export function render(gameState: GameState) {
|
|||
`<span class="score" data-tooltip="${t("play.score_tooltip")}">$${gameState.score}</span>`;
|
||||
|
||||
scoreDisplay.className =
|
||||
(gameState.computer_controlled && "hidden") ||
|
||||
(gameState.startParams.computer_controlled && "computer_controlled") ||
|
||||
(gameState.lastScoreIncrease > gameState.levelTime - 500 && "active") ||
|
||||
"";
|
||||
|
||||
// Clear
|
||||
if (!isOptionOn("basic") && level.svg && level.color === "#000000") {
|
||||
const skipN =
|
||||
isOptionOn("probabilistic_lighting") && liveCount(gameState.coins) > 150
|
||||
? 3
|
||||
: 0;
|
||||
const shouldSkip = (index) =>
|
||||
skipN ? (framesCounter + index) % (skipN + 1) !== 0 : false;
|
||||
|
||||
const haloScale = getHaloScale();
|
||||
startWork("render:halo:clear");
|
||||
|
||||
haloCanvasCtx.globalCompositeOperation = "source-over";
|
||||
haloCanvasCtx.globalAlpha = 0.99;
|
||||
haloCanvasCtx.globalAlpha = skipN ? 0.1 : 0.99;
|
||||
haloCanvasCtx.fillStyle = level.color;
|
||||
haloCanvasCtx.fillRect(0, 0, width / haloScale, height / haloScale);
|
||||
|
||||
const brightness = isOptionOn("extra_bright") ? 3 : 1;
|
||||
|
||||
haloCanvasCtx.globalCompositeOperation = "lighten";
|
||||
haloCanvasCtx.globalAlpha =
|
||||
0.1 + (0.5 * 10) / (liveCount(gameState.coins) + 10);
|
||||
forEachLiveOne(gameState.coins, (coin) => {
|
||||
startWork("render:halo:coins");
|
||||
forEachLiveOne(gameState.coins, (coin, index) => {
|
||||
if (shouldSkip(index)) return;
|
||||
const color = getCoinRenderColor(gameState, coin);
|
||||
drawFuzzyBall(
|
||||
haloCanvasCtx,
|
||||
|
@ -126,7 +146,9 @@ export function render(gameState: GameState) {
|
|||
);
|
||||
});
|
||||
|
||||
gameState.balls.forEach((ball) => {
|
||||
startWork("render:halo:balls");
|
||||
gameState.balls.forEach((ball, index) => {
|
||||
if (shouldSkip(index)) return;
|
||||
haloCanvasCtx.globalAlpha = 0.3 * (1 - ballTransparency(ball, gameState));
|
||||
drawFuzzyBall(
|
||||
haloCanvasCtx,
|
||||
|
@ -136,9 +158,12 @@ export function render(gameState: GameState) {
|
|||
ball.y / haloScale,
|
||||
);
|
||||
});
|
||||
|
||||
startWork("render:halo:bricks");
|
||||
haloCanvasCtx.globalAlpha = 0.05;
|
||||
gameState.bricks.forEach((color, index) => {
|
||||
if (!color) return;
|
||||
if (shouldSkip(index)) return;
|
||||
const x = brickCenterX(gameState, index),
|
||||
y = brickCenterY(gameState, index);
|
||||
drawFuzzyBall(
|
||||
|
@ -151,8 +176,10 @@ export function render(gameState: GameState) {
|
|||
);
|
||||
});
|
||||
|
||||
startWork("render:halo:particles");
|
||||
haloCanvasCtx.globalCompositeOperation = "screen";
|
||||
forEachLiveOne(gameState.particles, (flash) => {
|
||||
forEachLiveOne(gameState.particles, (flash, index) => {
|
||||
if (shouldSkip(index)) return;
|
||||
const { x, y, time, color, size, duration } = flash;
|
||||
const elapsed = gameState.levelTime - time;
|
||||
haloCanvasCtx.globalAlpha =
|
||||
|
@ -166,14 +193,16 @@ export function render(gameState: GameState) {
|
|||
);
|
||||
});
|
||||
|
||||
startWork("render:halo:scale_up");
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
|
||||
ctx.imageSmoothingEnabled = true;
|
||||
ctx.imageSmoothingQuality = "high";
|
||||
ctx.imageSmoothingEnabled = isOptionOn("smooth_lighting") || false;
|
||||
ctx.drawImage(haloCanvas, 0, 0, width, height);
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
|
||||
startWork("render:halo:pattern");
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "multiply";
|
||||
if (level.svg && background.width && background.complete) {
|
||||
|
@ -225,6 +254,7 @@ export function render(gameState: GameState) {
|
|||
ctx.fillRect(0, 0, width, height);
|
||||
}
|
||||
} else {
|
||||
startWork("render:halo-basic");
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
ctx.fillStyle = level.color || "#000";
|
||||
|
@ -237,9 +267,10 @@ export function render(gameState: GameState) {
|
|||
});
|
||||
}
|
||||
|
||||
startWork("render:explosionshake");
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
const lastExplosionDelay = Date.now() - gameState.lastExplosion + 5;
|
||||
const lastExplosionDelay = gameState.levelTime - gameState.lastExplosion + 5;
|
||||
const shaked = lastExplosionDelay < 200 && !isOptionOn("basic");
|
||||
if (shaked) {
|
||||
const amplitude =
|
||||
|
@ -249,7 +280,7 @@ export function render(gameState: GameState) {
|
|||
Math.sin(Date.now() + 36) * amplitude,
|
||||
);
|
||||
}
|
||||
|
||||
startWork("render:coins");
|
||||
// Coins
|
||||
ctx.globalAlpha = 1;
|
||||
forEachLiveOne(gameState.coins, (coin) => {
|
||||
|
@ -272,27 +303,27 @@ export function render(gameState: GameState) {
|
|||
coin.a,
|
||||
);
|
||||
});
|
||||
startWork("render:ball shade");
|
||||
// Black shadow around balls
|
||||
if (!isOptionOn("basic")) {
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
gameState.balls.forEach((ball) => {
|
||||
ctx.globalAlpha =
|
||||
Math.min(0.8, liveCount(gameState.coins) / 20) *
|
||||
(1 - ballTransparency(ball, gameState));
|
||||
|
||||
drawBall(
|
||||
ctx,
|
||||
level.color || "#000",
|
||||
gameState.ballSize * 6,
|
||||
ball.x,
|
||||
ball.y,
|
||||
);
|
||||
});
|
||||
}
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
gameState.balls.forEach((ball) => {
|
||||
ctx.globalAlpha =
|
||||
Math.min(0.8, liveCount(gameState.coins) / 20) *
|
||||
(1 - ballTransparency(ball, gameState));
|
||||
|
||||
drawBall(
|
||||
ctx,
|
||||
level.color || "#000",
|
||||
gameState.ballSize * 6,
|
||||
ball.x,
|
||||
ball.y,
|
||||
);
|
||||
});
|
||||
startWork("render:bricks");
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
renderAllBricks();
|
||||
|
||||
startWork("render:lights");
|
||||
ctx.globalCompositeOperation = "screen";
|
||||
forEachLiveOne(gameState.lights, (flash) => {
|
||||
const { x, y, time, color, size, duration } = flash;
|
||||
|
@ -309,6 +340,7 @@ export function render(gameState: GameState) {
|
|||
);
|
||||
});
|
||||
|
||||
startWork("render:texts");
|
||||
ctx.globalCompositeOperation = "screen";
|
||||
forEachLiveOne(gameState.texts, (flash) => {
|
||||
const { x, y, time, color, size, duration } = flash;
|
||||
|
@ -318,6 +350,7 @@ export function render(gameState: GameState) {
|
|||
drawText(ctx, flash.text, color, size, x, y - elapsed / 10);
|
||||
});
|
||||
|
||||
startWork("render:particles");
|
||||
forEachLiveOne(gameState.particles, (particle) => {
|
||||
const { x, y, time, color, size, duration } = particle;
|
||||
const elapsed = gameState.levelTime - time;
|
||||
|
@ -325,6 +358,8 @@ export function render(gameState: GameState) {
|
|||
ctx.globalCompositeOperation = "screen";
|
||||
drawBall(ctx, color, size, x, y);
|
||||
});
|
||||
|
||||
startWork("render:extra_life");
|
||||
if (gameState.perks.extra_life) {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
|
@ -339,9 +374,9 @@ export function render(gameState: GameState) {
|
|||
}
|
||||
}
|
||||
|
||||
startWork("render:balls");
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
|
||||
gameState.balls.forEach((ball) => {
|
||||
const drawingColor = gameState.ballsColor;
|
||||
const ballAlpha = 1 - ballTransparency(ball, gameState);
|
||||
|
@ -390,10 +425,10 @@ export function render(gameState: GameState) {
|
|||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
// The puck
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
|
||||
startWork("render:puck");
|
||||
ctx.globalAlpha = isMovingWhilePassiveIncome(gameState) ? 0.2 : 1;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
drawPuck(
|
||||
ctx,
|
||||
gameState.puckColor,
|
||||
|
@ -404,22 +439,20 @@ export function render(gameState: GameState) {
|
|||
gameState.perks.streak_shots && hasCombo ? getDashOffset(gameState) : -1,
|
||||
);
|
||||
|
||||
if (gameState.combo > 1) {
|
||||
startWork("render:combotext");
|
||||
|
||||
const spawns = coinsBoostedCombo(gameState);
|
||||
if (spawns > 1 && !isMovingWhilePassiveIncome(gameState)) {
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
const comboText = "x " + gameState.combo;
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
const comboText = spawns.toString();
|
||||
const comboTextWidth = (comboText.length * gameState.puckHeight) / 1.8;
|
||||
const totalWidth = comboTextWidth + gameState.coinSize * 2;
|
||||
const left = gameState.puckPosition - totalWidth / 2;
|
||||
|
||||
ctx.globalAlpha = gameState.combo > baseCombo(gameState) ? 1 : 0.3;
|
||||
if (totalWidth < gameState.puckWidth) {
|
||||
drawCoin(
|
||||
ctx,
|
||||
"#ffd300",
|
||||
gameState.coinSize,
|
||||
left + gameState.coinSize / 2,
|
||||
gameState.gameZoneHeight - gameState.puckHeight / 2,
|
||||
"#ffd300",
|
||||
0,
|
||||
);
|
||||
drawText(
|
||||
ctx,
|
||||
comboText,
|
||||
|
@ -429,6 +462,17 @@ export function render(gameState: GameState) {
|
|||
gameState.gameZoneHeight - gameState.puckHeight / 2,
|
||||
true,
|
||||
);
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
drawCoin(
|
||||
ctx,
|
||||
"#ffd300",
|
||||
gameState.coinSize,
|
||||
left + gameState.coinSize / 2,
|
||||
gameState.gameZoneHeight - gameState.puckHeight / 2,
|
||||
"#ffd300",
|
||||
0,
|
||||
);
|
||||
} else {
|
||||
drawText(
|
||||
ctx,
|
||||
|
@ -443,8 +487,8 @@ export function render(gameState: GameState) {
|
|||
);
|
||||
}
|
||||
}
|
||||
startWork("render:borders");
|
||||
// Borders
|
||||
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
|
@ -457,51 +501,55 @@ export function render(gameState: GameState) {
|
|||
|
||||
if (gameState.offsetXRoundedDown) {
|
||||
// draw outside of gaming area to avoid capturing borders in recordings
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redLeftSide && "#FF0000") || "#FFFFFF",
|
||||
gameState.offsetXRoundedDown - 1,
|
||||
0,
|
||||
gameState.offsetXRoundedDown - 1,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redRightSide && "#FF0000") || "#FFFFFF",
|
||||
width - gameState.offsetXRoundedDown + 1,
|
||||
0,
|
||||
width - gameState.offsetXRoundedDown + 1,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
if (gameState.perks.left_is_lava < 2)
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redLeftSide && "#FF0000") || "#FFFFFF",
|
||||
gameState.offsetXRoundedDown - 1,
|
||||
0,
|
||||
gameState.offsetXRoundedDown - 1,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
if (gameState.perks.right_is_lava < 2)
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redRightSide && "#FF0000") || "#FFFFFF",
|
||||
width - gameState.offsetXRoundedDown + 1,
|
||||
0,
|
||||
width - gameState.offsetXRoundedDown + 1,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
} else {
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redLeftSide && "#FF0000") || "",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
if (gameState.perks.left_is_lava < 2)
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redLeftSide && "#FF0000") || "",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redRightSide && "#FF0000") || "",
|
||||
width - 1,
|
||||
0,
|
||||
width - 1,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
if (gameState.perks.right_is_lava < 2)
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(redRightSide && "#FF0000") || "",
|
||||
width - 1,
|
||||
0,
|
||||
width - 1,
|
||||
height,
|
||||
1,
|
||||
);
|
||||
}
|
||||
if (redTop)
|
||||
|
||||
if (redTop && gameState.perks.top_is_lava < 2)
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
|
@ -513,42 +561,63 @@ export function render(gameState: GameState) {
|
|||
1,
|
||||
);
|
||||
|
||||
startWork("render:bottom_line");
|
||||
ctx.globalAlpha = 1;
|
||||
const corner = getCornerOffset(gameState);
|
||||
drawStraightLine(
|
||||
ctx,
|
||||
gameState,
|
||||
(hasCombo && gameState.perks.compound_interest && "#FF0000") ||
|
||||
(isOptionOn("mobile-mode") && "#FFFFFF") ||
|
||||
(isOptionOn("mobile-mode") && "#666666") ||
|
||||
(corner && "#666666") ||
|
||||
"",
|
||||
gameState.offsetXRoundedDown,
|
||||
gameState.gameZoneHeight,
|
||||
width - gameState.offsetXRoundedDown,
|
||||
gameState.gameZoneHeight,
|
||||
gameState.offsetXRoundedDown - corner,
|
||||
gameState.gameZoneHeight - 1,
|
||||
width - gameState.offsetXRoundedDown + corner,
|
||||
gameState.gameZoneHeight - 1,
|
||||
1,
|
||||
);
|
||||
|
||||
startWork("render:contrast");
|
||||
if (
|
||||
!isOptionOn("basic") &&
|
||||
isOptionOn("contrast") &&
|
||||
level.svg &&
|
||||
level.color === "#000000"
|
||||
) {
|
||||
ctx.imageSmoothingEnabled = true;
|
||||
// haloCanvasCtx.globalCompositeOperation = 'multiply';
|
||||
// haloCanvasCtx.fillRect(0,0,haloCanvas.width,haloCanvas.height)
|
||||
haloCanvasCtx.fillStyle = "#FFFFFF";
|
||||
haloCanvasCtx.globalAlpha = 0.25;
|
||||
haloCanvasCtx.globalCompositeOperation = "screen";
|
||||
haloCanvasCtx.fillRect(0, 0, haloCanvas.width, haloCanvas.height);
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "overlay";
|
||||
ctx.imageSmoothingEnabled = isOptionOn("smooth_lighting") || false;
|
||||
|
||||
if (isOptionOn("probabilistic_lighting")) {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "soft-light";
|
||||
} else {
|
||||
haloCanvasCtx.fillStyle = "#FFFFFF";
|
||||
haloCanvasCtx.globalAlpha = 0.25;
|
||||
haloCanvasCtx.globalCompositeOperation = "screen";
|
||||
haloCanvasCtx.fillRect(0, 0, haloCanvas.width, haloCanvas.height);
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = "overlay";
|
||||
}
|
||||
|
||||
ctx.drawImage(haloCanvas, 0, 0, width, height);
|
||||
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
}
|
||||
|
||||
startWork("render:text_under_puck");
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
ctx.globalAlpha = 1;
|
||||
if (isOptionOn("mobile-mode") && gameState.startParams.computer_controlled) {
|
||||
drawText(
|
||||
ctx,
|
||||
"breakout.lecaro.me?autoplay",
|
||||
gameState.puckColor,
|
||||
gameState.puckHeight,
|
||||
gameState.canvasWidth / 2,
|
||||
gameState.gameZoneHeight +
|
||||
(gameState.canvasHeight - gameState.gameZoneHeight) / 2,
|
||||
);
|
||||
}
|
||||
if (isOptionOn("mobile-mode") && !gameState.running) {
|
||||
drawText(
|
||||
ctx,
|
||||
|
@ -561,6 +630,10 @@ export function render(gameState: GameState) {
|
|||
);
|
||||
}
|
||||
|
||||
startWork("render:askForWakeLock");
|
||||
askForWakeLock(gameState);
|
||||
|
||||
startWork("render:resetTransform");
|
||||
if (shaked) {
|
||||
ctx.resetTransform();
|
||||
}
|
||||
|
@ -569,22 +642,25 @@ export function render(gameState: GameState) {
|
|||
function drawStraightLine(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
gameState: GameState,
|
||||
mode: "#FFFFFF" | "" | "#FF0000",
|
||||
mode: "#FFFFFF" | "" | "#FF0000" | string,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
alpha = 1,
|
||||
) {
|
||||
x1 = Math.round(x1);
|
||||
y1 = Math.round(y1);
|
||||
x2 = Math.round(x2);
|
||||
y2 = Math.round(y2);
|
||||
ctx.globalAlpha = alpha;
|
||||
if (!mode) return;
|
||||
ctx.strokeStyle = mode;
|
||||
if (mode == "#FF0000") {
|
||||
ctx.strokeStyle = "#FF0000";
|
||||
ctx.lineDashOffset = getDashOffset(gameState);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash(redBorderDash);
|
||||
} else {
|
||||
ctx.strokeStyle = "#FFFFFF";
|
||||
ctx.lineWidth = 1;
|
||||
}
|
||||
ctx.beginPath();
|
||||
|
@ -609,15 +685,12 @@ export function renderAllBricks() {
|
|||
const redBorderOnBricksWithWrongColor =
|
||||
hasCombo && gameState.perks.picky_eater && isPickyEatingPossible(gameState);
|
||||
|
||||
const redColorOnAllBricks = hasCombo && isMovingWhilePassiveIncome(gameState);
|
||||
|
||||
const redRowReach = reachRedRowIndex(gameState);
|
||||
const { clairvoyant } = gameState.perks;
|
||||
let offset = getDashOffset(gameState);
|
||||
if (
|
||||
!(
|
||||
redBorderOnBricksWithWrongColor ||
|
||||
redColorOnAllBricks ||
|
||||
redRowReach !== -1 ||
|
||||
gameState.perks.zen
|
||||
)
|
||||
|
@ -638,8 +711,6 @@ export function renderAllBricks() {
|
|||
"_" +
|
||||
redBorderOnBricksWithWrongColor +
|
||||
"_" +
|
||||
redColorOnAllBricks +
|
||||
"_" +
|
||||
gameState.ballsColor +
|
||||
"_" +
|
||||
gameState.perks.pierce_color +
|
||||
|
@ -674,8 +745,7 @@ export function renderAllBricks() {
|
|||
color !== "black" &&
|
||||
redBorderOnBricksWithWrongColor) ||
|
||||
(hasCombo && gameState.perks.zen && color === "black") ||
|
||||
redBecauseOfReach ||
|
||||
redColorOnAllBricks;
|
||||
redBecauseOfReach;
|
||||
|
||||
canctx.globalCompositeOperation = "source-over";
|
||||
drawBrick(
|
||||
|
@ -901,6 +971,7 @@ export function drawFuzzyBall(
|
|||
x: number,
|
||||
y: number,
|
||||
) {
|
||||
width = Math.max(width, 2);
|
||||
const key = "fuzzy-circle" + color + "_" + width;
|
||||
if (!color?.startsWith("#")) debugger;
|
||||
|
||||
|
@ -1101,13 +1172,26 @@ export function getDashOffset(gameState: GameState) {
|
|||
return Math.floor(((gameState.levelTime % 500) / 500) * 10) % 10;
|
||||
}
|
||||
|
||||
function getCoinRenderColor(gameState: GameState, coin: Coin) {
|
||||
let wakeLock = null,
|
||||
wakeLockPending = false;
|
||||
function askForWakeLock(gameState: GameState) {
|
||||
if (
|
||||
gameState.perks.metamorphosis ||
|
||||
isOptionOn("colorful_coins") ||
|
||||
gameState.perks.hypnosis ||
|
||||
gameState.perks.rainbow
|
||||
)
|
||||
return coin.color;
|
||||
return "#ffd300";
|
||||
gameState.startParams.computer_controlled &&
|
||||
!wakeLock &&
|
||||
!wakeLockPending
|
||||
) {
|
||||
wakeLockPending = true;
|
||||
try {
|
||||
navigator.wakeLock.request("screen").then((lock) => {
|
||||
wakeLock = lock;
|
||||
wakeLockPending = false;
|
||||
lock.addEventListener("release", () => {
|
||||
// the wake lock has been released
|
||||
wakeLock = null;
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn("askForWakeLock error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { getHistory } from "./gameOver";
|
||||
import { icons } from "./loadGameData";
|
||||
import { appVersion, icons } from "./loadGameData";
|
||||
import { t } from "./i18n/i18n";
|
||||
import { asyncAlert } from "./asyncAlert";
|
||||
import { rawUpgrades } from "./upgrades";
|
||||
import { getSettingValue, setSettingValue } from "./settings";
|
||||
|
||||
export function runHistoryViewerMenuEntry() {
|
||||
const history = getHistory();
|
||||
|
@ -41,6 +42,11 @@ export function runHistoryViewerMenuEntry() {
|
|||
})),
|
||||
];
|
||||
while (true) {
|
||||
const hasCurrentVersion = history.find(
|
||||
(r) => r.appVersion === appVersion,
|
||||
);
|
||||
const hasPastVersion = history.find((r) => r.appVersion !== appVersion);
|
||||
|
||||
const header = columns
|
||||
.map(
|
||||
(c, ci) =>
|
||||
|
@ -49,6 +55,12 @@ export function runHistoryViewerMenuEntry() {
|
|||
.join("");
|
||||
const toString = (v) => v.toString();
|
||||
const tbody = history
|
||||
.filter(
|
||||
(r) =>
|
||||
!hasCurrentVersion ||
|
||||
r.appVersion === appVersion ||
|
||||
getSettingValue("show_old_versions_in_stats", false),
|
||||
)
|
||||
.sort(
|
||||
(a, b) =>
|
||||
sortDir * (columns[sort].field(a) - columns[sort].field(b)),
|
||||
|
@ -77,6 +89,14 @@ export function runHistoryViewerMenuEntry() {
|
|||
<tbody>${tbody}</tbody>
|
||||
</table>
|
||||
`,
|
||||
hasPastVersion &&
|
||||
hasCurrentVersion && {
|
||||
icon: getSettingValue("show_old_versions_in_stats", false)
|
||||
? icons["icon:checkmark_checked"]
|
||||
: icons["icon:checkmark_unchecked"],
|
||||
value: "toggle",
|
||||
text: t("history.include_past_versions"),
|
||||
},
|
||||
],
|
||||
});
|
||||
if (!result) return;
|
||||
|
@ -89,6 +109,12 @@ export function runHistoryViewerMenuEntry() {
|
|||
sort = newSort;
|
||||
}
|
||||
}
|
||||
if (result === "toggle") {
|
||||
setSettingValue(
|
||||
"show_old_versions_in_stats",
|
||||
!getSettingValue("show_old_versions_in_stats", false),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,44 +1,84 @@
|
|||
// Settings
|
||||
|
||||
let cachedSettings: { [key: string]: unknown } = {};
|
||||
import { toast } from "./toast";
|
||||
|
||||
export function getSettingValue<T>(key: string, defaultValue: T) {
|
||||
if (typeof cachedSettings[key] == "undefined") {
|
||||
let cachedSettings: { [key: string]: unknown } = {};
|
||||
let warnedUserAboutLSIssue = false;
|
||||
|
||||
try {
|
||||
for (let key in localStorage) {
|
||||
try {
|
||||
const ls = localStorage.getItem(key);
|
||||
if (ls) cachedSettings[key] = JSON.parse(ls) as T;
|
||||
cachedSettings[key] = JSON.parse(localStorage.getItem(key) || "null");
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
if (!warnedUserAboutLSIssue) {
|
||||
warnedUserAboutLSIssue = true;
|
||||
toast(`Storage issue : ${(e as Error)?.message}`);
|
||||
}
|
||||
console.warn("Reading " + key, e);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
|
||||
export function getSettingValue<T>(key: string, defaultValue: T) {
|
||||
return (cachedSettings[key] as T) ?? defaultValue;
|
||||
}
|
||||
|
||||
// We avoid using localstorage synchronously for perf reasons
|
||||
let needsSaving: Set<string> = new Set();
|
||||
|
||||
export function setSettingValue<T>(key: string, value: T) {
|
||||
needsSaving.add(key);
|
||||
cachedSettings[key] = value;
|
||||
}
|
||||
|
||||
export function commitSettingsChangesToLocalStorage() {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(value));
|
||||
for (let key of needsSaving) {
|
||||
localStorage.setItem(key, JSON.stringify(cachedSettings[key]));
|
||||
}
|
||||
needsSaving.clear();
|
||||
} catch (e) {
|
||||
if (!warnedUserAboutLSIssue) {
|
||||
warnedUserAboutLSIssue = true;
|
||||
toast(`Storage issue : ${(e as Error)?.message}`);
|
||||
}
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(() => commitSettingsChangesToLocalStorage(), 500);
|
||||
|
||||
export function getTotalScore() {
|
||||
return getSettingValue("breakout_71_total_score", 0);
|
||||
}
|
||||
|
||||
export function getCurrentMaxCoins() {
|
||||
return Math.pow(2, getSettingValue("max_coins", 1)) * 200;
|
||||
return Math.pow(2, getSettingValue("max_coins", 2)) * 200;
|
||||
}
|
||||
|
||||
export function getCurrentMaxParticles() {
|
||||
return Math.pow(2, getSettingValue("max_particles", 1)) * 200;
|
||||
return getCurrentMaxCoins();
|
||||
}
|
||||
|
||||
export function cycleMaxCoins() {
|
||||
setSettingValue("max_coins", (getSettingValue("max_coins", 1) + 1) % 6);
|
||||
setSettingValue("max_coins", (getSettingValue("max_coins", 2) + 1) % 7);
|
||||
}
|
||||
export function cycleMaxParticles() {
|
||||
setSettingValue(
|
||||
"max_particles",
|
||||
(getSettingValue("max_particles", 1) + 1) % 6,
|
||||
);
|
||||
|
||||
let asked = false;
|
||||
|
||||
export async function askForPersistentStorage() {
|
||||
if (asked) return;
|
||||
asked = true;
|
||||
if (!navigator.storage) return;
|
||||
if (!navigator.storage.persist) return;
|
||||
if (!navigator.storage.persisted) return;
|
||||
if (await navigator.storage.persisted()) {
|
||||
return;
|
||||
}
|
||||
const persistent = await navigator.storage.persist();
|
||||
if (!persistent) {
|
||||
console.warn("No storage granted");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ export function playPendingSounds(gameState: GameState) {
|
|||
};
|
||||
if (ex.vol) {
|
||||
sounds[soundName](
|
||||
Math.min(2, ex.vol),
|
||||
// In stress test, dim the sounds but play them
|
||||
Math.min(1, ex.vol),
|
||||
pixelsToPan(gameState, ex.x),
|
||||
gameState.combo,
|
||||
);
|
||||
|
@ -25,13 +26,21 @@ export function playPendingSounds(gameState: GameState) {
|
|||
}
|
||||
}
|
||||
export const sounds = {
|
||||
wallBeep: (vol: number, pan: number, combo: number) => {
|
||||
wallBeep: (volume: number, pan: number) => {
|
||||
if (!isOptionOn("sound")) return;
|
||||
createSingleBounceSound(800, pan, vol);
|
||||
|
||||
createSingleBounceSound(800, pan, volume);
|
||||
},
|
||||
|
||||
plouf: (volume: number, pan: number) => {
|
||||
if (!isOptionOn("sound")) return;
|
||||
createSingleBounceSound(500, pan, volume * 0.5);
|
||||
// createWaterDropSound(800, pan, volume*0.2, 0.2,'triangle')
|
||||
},
|
||||
|
||||
comboIncreaseMaybe: (volume: number, pan: number, combo: number) => {
|
||||
if (!isOptionOn("sound")) return;
|
||||
|
||||
let delta = 0;
|
||||
if (!isNaN(lastComboPlayed)) {
|
||||
if (lastComboPlayed < combo) delta = 1;
|
||||
|
|
28
src/toast.ts
28
src/toast.ts
|
@ -1,17 +1,15 @@
|
|||
let onScreen = 0;
|
||||
|
||||
export function toast(html) {
|
||||
const div = document.createElement("div");
|
||||
div.classList = "toast";
|
||||
let div = document.createElement("div");
|
||||
div.classList = "hidden toast";
|
||||
document.body.appendChild(div);
|
||||
let timeout: NodeJS.Timeout | undefined;
|
||||
export function toast(html: string) {
|
||||
div.classList = "toast visible";
|
||||
div.innerHTML = html;
|
||||
const lasts = 1500 + onScreen * 200;
|
||||
div.style.animationDuration = lasts + "ms";
|
||||
div.style.top = 40 + onScreen * 50 + "px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
onScreen++;
|
||||
setTimeout(() => {
|
||||
div.remove();
|
||||
onScreen--;
|
||||
}, lasts);
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
timeout = setTimeout(() => {
|
||||
timeout = undefined;
|
||||
div.classList = "hidden toast";
|
||||
}, 1500);
|
||||
}
|
||||
|
|
14
src/types.d.ts
vendored
14
src/types.d.ts
vendored
|
@ -7,7 +7,6 @@ export type RawLevel = {
|
|||
name: string;
|
||||
size: number;
|
||||
bricks: string;
|
||||
svg: number | null;
|
||||
color: string;
|
||||
credit?: string;
|
||||
};
|
||||
|
@ -85,6 +84,7 @@ export type Coin = {
|
|||
destroyed?: boolean;
|
||||
collidedLastFrame?: boolean;
|
||||
metamorphosisPoints: number;
|
||||
floatingTime: number;
|
||||
};
|
||||
export type Ball = {
|
||||
x: number;
|
||||
|
@ -103,6 +103,7 @@ export type Ball = {
|
|||
hitSinceBounce: number;
|
||||
// Brick was really broken ,but could have been respawned as a bomb
|
||||
brokenSinceBounce: number;
|
||||
sidesHitsSinceBounce: number;
|
||||
sapperUses: number;
|
||||
destroyed?: boolean;
|
||||
};
|
||||
|
@ -252,8 +253,6 @@ export type GameState = {
|
|||
levelSpawnedCoins: number;
|
||||
levelLostCoins: number;
|
||||
|
||||
// MAX_COINS: number;
|
||||
// MAX_PARTICLES: number;
|
||||
puckColor: colorString;
|
||||
ballSize: number;
|
||||
coinSize: number;
|
||||
|
@ -266,6 +265,7 @@ export type GameState = {
|
|||
lastOffered: Partial<{ [k in PerkId]: number }>;
|
||||
levelTime: number;
|
||||
lastPuckMove: number;
|
||||
lastZenComboIncrease: number;
|
||||
winAt: number;
|
||||
levelWallBounces: number;
|
||||
autoCleanUses: number;
|
||||
|
@ -277,19 +277,23 @@ export type GameState = {
|
|||
explode: { vol: number; x: number };
|
||||
lifeLost: { vol: number; x: number };
|
||||
coinCatch: { vol: number; x: number };
|
||||
plouf: { vol: number; x: number };
|
||||
colorChange: { vol: number; x: number };
|
||||
};
|
||||
rerolls: number;
|
||||
creative: boolean;
|
||||
computer_controlled: boolean;
|
||||
startParams: RunParams;
|
||||
};
|
||||
|
||||
export type RunParams = {
|
||||
level?: string;
|
||||
level?: Level;
|
||||
levelToAvoid?: string;
|
||||
perkToAvoid?: PerkId;
|
||||
perks?: Partial<PerksMap>;
|
||||
computer_controlled?: boolean;
|
||||
isEditorTrialRun?: number;
|
||||
isCreativeRun?: boolean;
|
||||
stress?: boolean;
|
||||
};
|
||||
export type OptionDef = {
|
||||
default: boolean;
|
||||
|
|
|
@ -190,9 +190,7 @@ export const rawUpgrades = [
|
|||
max: 2,
|
||||
name: t("upgrades.smaller_puck.name"),
|
||||
help: (lvl: number) =>
|
||||
lvl == 1
|
||||
? t("upgrades.smaller_puck.tooltip")
|
||||
: t("upgrades.smaller_puck.help_plural"),
|
||||
t("upgrades.smaller_puck.tooltip", { percent: 50 * lvl }),
|
||||
fullHelp: t("upgrades.smaller_puck.verbose_description"),
|
||||
},
|
||||
{
|
||||
|
@ -721,15 +719,13 @@ export const rawUpgrades = [
|
|||
id: "fountain_toss",
|
||||
max: 7,
|
||||
name: t("upgrades.fountain_toss.name"),
|
||||
help: (lvl: number) =>
|
||||
t("upgrades.fountain_toss.tooltip", { lvl, max: lvl * 30 }),
|
||||
help: () => t("upgrades.fountain_toss.tooltip"),
|
||||
fullHelp: t("upgrades.fountain_toss.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 175000,
|
||||
gift: false,
|
||||
|
||||
id: "limitless",
|
||||
max: 1,
|
||||
name: t("upgrades.limitless.name"),
|
||||
|
@ -766,7 +762,8 @@ export const rawUpgrades = [
|
|||
id: "transparency",
|
||||
max: 3,
|
||||
name: t("upgrades.transparency.name"),
|
||||
help: (lvl: number) => t("upgrades.transparency.tooltip", { lvl }),
|
||||
help: (lvl: number) =>
|
||||
t("upgrades.transparency.tooltip", { lvl, percent: lvl * 50 }),
|
||||
fullHelp: t("upgrades.transparency.verbose_description"),
|
||||
},
|
||||
{
|
||||
|
@ -818,10 +815,95 @@ export const rawUpgrades = [
|
|||
threshold: 215000,
|
||||
gift: false,
|
||||
id: "bricks_attract_ball",
|
||||
max: 3,
|
||||
max: 1,
|
||||
name: t("upgrades.bricks_attract_ball.name"),
|
||||
help: (lvl: number) =>
|
||||
t("upgrades.bricks_attract_ball.tooltip", { count: lvl * 3 }),
|
||||
fullHelp: t("upgrades.bricks_attract_ball.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 220000,
|
||||
gift: false,
|
||||
id: "buoy",
|
||||
max: 3,
|
||||
name: t("upgrades.buoy.name"),
|
||||
help: (lvl: number) => t("upgrades.buoy.tooltip", { duration: lvl * 0.5 }),
|
||||
fullHelp: t("upgrades.buoy.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 225000,
|
||||
gift: false,
|
||||
id: "ottawa_treaty",
|
||||
max: 1,
|
||||
name: t("upgrades.ottawa_treaty.name"),
|
||||
help: () => t("upgrades.ottawa_treaty.tooltip"),
|
||||
fullHelp: t("upgrades.ottawa_treaty.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 230000,
|
||||
gift: false,
|
||||
id: "three_cushion",
|
||||
max: 1,
|
||||
name: t("upgrades.three_cushion.name"),
|
||||
help: (lvl: number) =>
|
||||
t("upgrades.three_cushion.tooltip", { max: lvl * 3 }),
|
||||
fullHelp: t("upgrades.three_cushion.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 235000,
|
||||
gift: false,
|
||||
id: "sticky_coins",
|
||||
max: 1,
|
||||
name: t("upgrades.sticky_coins.name"),
|
||||
help: (lvl: number) => t("upgrades.sticky_coins.tooltip"),
|
||||
fullHelp: t("upgrades.sticky_coins.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 235000,
|
||||
gift: false,
|
||||
id: "double_or_nothing",
|
||||
max: 3,
|
||||
name: t("upgrades.double_or_nothing.name"),
|
||||
help: (lvl: number) =>
|
||||
t("upgrades.double_or_nothing.tooltip", {
|
||||
percent: lvl * 10,
|
||||
multiplier: 1 + lvl,
|
||||
}),
|
||||
fullHelp: t("upgrades.double_or_nothing.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 240000,
|
||||
gift: false,
|
||||
id: "wrap_left",
|
||||
max: 1,
|
||||
name: t("upgrades.wrap_left.name"),
|
||||
help: () => t("upgrades.wrap_left.tooltip"),
|
||||
fullHelp: t("upgrades.wrap_left.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "",
|
||||
threshold: 245000,
|
||||
gift: false,
|
||||
id: "wrap_right",
|
||||
max: 1,
|
||||
name: t("upgrades.wrap_right.name"),
|
||||
help: () => t("upgrades.wrap_right.tooltip"),
|
||||
fullHelp: t("upgrades.wrap_right.verbose_description"),
|
||||
},
|
||||
{
|
||||
requires: "multiball",
|
||||
threshold: 245000,
|
||||
gift: false,
|
||||
id: "happy_family",
|
||||
max: 1,
|
||||
name: t("upgrades.happy_family.name"),
|
||||
help: () => t("upgrades.happy_family.tooltip"),
|
||||
fullHelp: t("upgrades.happy_family.verbose_description"),
|
||||
},
|
||||
] as const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue