mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
commit
99220fe889
22
README.md
22
README.md
@ -2,28 +2,30 @@
|
||||
|
||||
<img src="https://i.imgur.com/Y5Z2iqQ.png" alt="shapez.io Logo">
|
||||
|
||||
This is the source code for shapez.io, an open source base building game inspired by factorio.
|
||||
This is the source code for shapez.io, an open source base building game inspired by Factorio.
|
||||
|
||||
Your goal is to produce shapes by cutting, rotating, merging and painting parts of shapes.
|
||||
|
||||
## Playing
|
||||
|
||||
You can already play it on https://shapez.io
|
||||
You can already play it [here](https://shapez.io).
|
||||
|
||||
## Building
|
||||
|
||||
- Make sure ffmpeg is on your path
|
||||
- Install yarn and node 10
|
||||
- Make sure git `git lfs` extension is on your path
|
||||
- Run `git lfs pull` to download sound assets
|
||||
- Make sure `ffmpeg` is on your path
|
||||
- Install Yarn and Node.js 10
|
||||
- Run `yarn` in the root folder, then run `yarn` in the `gulp/` folder
|
||||
- Cd into `gulp` and run `yarn gulp`: It should now open in your browser
|
||||
- Cd into `gulp` and run `yarn gulp` - it should now open in your browser
|
||||
|
||||
**Notice**: This will give you a debug build with several debugging flags enabled. If you want to disable them, check `config.js`
|
||||
**Notice**: This will produce a debug build with several debugging flags enabled. If you want to disable them, modify `config.js`.
|
||||
|
||||
## Contributing
|
||||
|
||||
Since this game is in the more or less early development, I will only accept pull requests which add an immediate benefit. Please understand that low quality PR's might be closed by me with a short comment explaining why.
|
||||
|
||||
If you want to add a new feature or in generally contribute I recommend to get in touch with me on discord:
|
||||
If you want to add a new feature or in generally contribute I recommend to get in touch with me on Discord:
|
||||
|
||||
<a href="https://discord.com/invite/HN7EVzV" target="_blank">
|
||||
<img src="https://i.imgur.com/SoawBhW.png" alt="discord logo" width="100">
|
||||
@ -34,10 +36,10 @@ If you want to add a new feature or in generally contribute I recommend to get i
|
||||
The game is based on a custom engine which itself is based on the YORG.io 3 game egine (Actually it shares almost the same core).
|
||||
The code within the engine is relatively clean with some code for the actual game on top being hacky.
|
||||
|
||||
This project is based on ES5. Some es6 features are used but most of them are too slow, especially when polyfilled. For example, `.forEach` is only used within non-critical loops since its slower than a plain for loop.
|
||||
This project is based on ES5. Some ES2015 features are used but most of them are too slow, especially when polyfilled. For example, `Array.prototype.forEach` is only used within non-critical loops since its slower than a plain for loop.
|
||||
|
||||
### Assets
|
||||
|
||||
For most assets I use photoshop, you can find them in `assets/`.
|
||||
For most assets I use Adobe Photoshop, you can find them in `assets/`.
|
||||
|
||||
You will need a <a href="https://www.codeandweb.com/texturepacker" target="_blank">texture packer</a> license in order to regenerate the atlas. If you don't have one but you want to contribute assets, let me know and I might compile it for you.
|
||||
You will need a <a href="https://www.codeandweb.com/texturepacker" target="_blank">Texture Packer</a> license in order to regenerate the atlas. If you don't have one but want to contribute assets, let me know and I might compile it for you.
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 904 KiB After Width: | Height: | Size: 2.5 MiB |
BIN
artwork/itch.io/screenshots/8.png
Normal file
BIN
artwork/itch.io/screenshots/8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
17
artwork/thirdparty/kongregate/iframe.html
vendored
Normal file
17
artwork/thirdparty/kongregate/iframe.html
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Iframe test</title>
|
||||
</head>
|
||||
|
||||
<body style="background: #333438; color: #eee;"></body>
|
||||
<iframe
|
||||
src="http://localhost:3005?embed=kongregate"
|
||||
width="800"
|
||||
height="600"
|
||||
scrolling="auto"
|
||||
frameborder="0"
|
||||
border="0"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</html>
|
4
artwork/thirdparty/kongregate/index.html
vendored
4
artwork/thirdparty/kongregate/index.html
vendored
@ -2,11 +2,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Redirecting to shapez.io</title>
|
||||
<meta http-equiv="refresh" content="0; URL=https://shapez.io" />
|
||||
<meta http-equiv="refresh" content="0; URL=https://shapez.io?embed=kongregate" />
|
||||
</head>
|
||||
|
||||
<body style="background: #333438; color: #eee;">
|
||||
Redirecting you to
|
||||
<a href="https://shapez.io" style="color: #39f; text-decoration: none;">shapez.io</a>
|
||||
<a href="https://shapez.io?embed=kongregate" style="color: #39f; text-decoration: none;">shapez.io</a>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
const nodeVersion = process.versions.node.split(".")[0];
|
||||
if (nodeVersion !== "10") {
|
||||
console.error("This cli requires exactly Node 10. You are using node " + nodeVersion);
|
||||
console.error("This cli requires exactly Node.js 10. You are using Node.js " + nodeVersion);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -14,6 +14,23 @@ const path = require("path");
|
||||
const deleteEmpty = require("delete-empty");
|
||||
const execSync = require("child_process").execSync;
|
||||
|
||||
const lfsOutput = execSync("git lfs install", { encoding: "utf-8" });
|
||||
if (!lfsOutput.toLowerCase().includes("git lfs initialized")) {
|
||||
console.error(`
|
||||
Git LFS is not installed, unable to build.
|
||||
|
||||
To install Git LFS on Linux:
|
||||
- Arch:
|
||||
sudo pacman -S git-lfs
|
||||
- Debian/Ubuntu:
|
||||
sudo apt install git-lfs
|
||||
|
||||
For other systems, see:
|
||||
https://github.com/git-lfs/git-lfs/wiki/Installation
|
||||
`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Load other plugins dynamically
|
||||
const $ = require("gulp-load-plugins")({
|
||||
scope: ["devDependencies"],
|
||||
|
@ -142,6 +142,11 @@ function gulptasksStandalone($, gulp, buildFolder) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(appPath, "LICENSE"),
|
||||
fs.readFileSync(path.join(__dirname, "..", "LICENSE"))
|
||||
);
|
||||
|
||||
const playablePath = appPath + "_playable";
|
||||
fse.copySync(appPath, playablePath);
|
||||
fs.writeFileSync(path.join(playablePath, "steam_appid.txt"), "1134480");
|
||||
@ -174,8 +179,8 @@ function gulptasksStandalone($, gulp, buildFolder) {
|
||||
"standalone.package.prod",
|
||||
$.sequence("standalone.prepare", [
|
||||
"standalone.package.prod.win64",
|
||||
// "standalone.package.prod.win32",
|
||||
// "standalone.package.prod.linux64",
|
||||
// "standalone.package.prod.win32",
|
||||
// "standalone.package.prod.linux32",
|
||||
// "standalone.package.prod.darwin64"
|
||||
])
|
||||
|
@ -117,6 +117,10 @@
|
||||
overflow-y: auto;
|
||||
pointer-events: all;
|
||||
@include S(width, 350px);
|
||||
|
||||
> strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
> .buttons {
|
||||
@ -143,6 +147,32 @@
|
||||
background-color: $colorRedBright;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.timedButton {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: unset;
|
||||
z-index: 5;
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
background: rgba(#fff, 0.6);
|
||||
@include InlineAnimation(5s linear) {
|
||||
0% {
|
||||
width: 100%;
|
||||
}
|
||||
100% {
|
||||
width: 0%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,13 @@
|
||||
.changes {
|
||||
@include SuperSmallText;
|
||||
@include S(padding-left, 20px);
|
||||
strong {
|
||||
background: $colorBlueBright;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
@include S(padding, 1px, 2px);
|
||||
@include S(margin-right, 3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,14 @@
|
||||
}
|
||||
|
||||
.changelogDialogEntry {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
background: #eef1f4;
|
||||
|
||||
.version {
|
||||
@include Heading;
|
||||
}
|
||||
@ -25,7 +28,14 @@
|
||||
|
||||
.changes {
|
||||
@include SuperSmallText;
|
||||
@include S(padding-left, 20px);
|
||||
@include S(padding-left, 15px);
|
||||
strong {
|
||||
background: $colorBlueBright;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
@include S(padding, 1px, 2px);
|
||||
@include S(margin-right, 3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,12 +146,8 @@ export class Application {
|
||||
}
|
||||
this.analytics = new GoogleAnalyticsImpl(this);
|
||||
|
||||
if (queryParamOptions.betaMode) {
|
||||
this.gameAnalytics = new NoGameAnalytics(this);
|
||||
} else {
|
||||
this.gameAnalytics = new ShapezGameAnalytics(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all game states
|
||||
@ -232,6 +228,7 @@ export class Application {
|
||||
* @param {Event} event
|
||||
*/
|
||||
handleVisibilityChange(event) {
|
||||
window.focus();
|
||||
const pageVisible = !document[pageHiddenPropName];
|
||||
if (pageVisible !== this.pageVisible) {
|
||||
this.pageVisible = pageVisible;
|
||||
@ -271,6 +268,7 @@ export class Application {
|
||||
|
||||
onAppRenderableStateChanged(renderable) {
|
||||
logger.log("Application renderable:", renderable);
|
||||
window.focus();
|
||||
if (!renderable) {
|
||||
this.stateMgr.getCurrentState().onAppPause();
|
||||
} else {
|
||||
@ -301,8 +299,7 @@ export class Application {
|
||||
logSection("BEFORE UNLOAD HANDLER", "#f77");
|
||||
|
||||
if (!G_IS_DEV && this.stateMgr.getCurrentState().getHasUnloadConfirmation()) {
|
||||
if (G_IS_STANDALONE) {
|
||||
} else {
|
||||
if (!G_IS_STANDALONE) {
|
||||
// Need to show a "Are you sure you want to exit"
|
||||
event.preventDefault();
|
||||
event.returnValue = "Are you sure you want to exit?";
|
||||
@ -314,6 +311,7 @@ export class Application {
|
||||
* Boots the application
|
||||
*/
|
||||
boot() {
|
||||
console.log("Booting ...");
|
||||
this.registerStates();
|
||||
this.registerEventListeners();
|
||||
|
||||
@ -330,6 +328,8 @@ export class Application {
|
||||
this.ticker.frameEmitted.add(this.onFrameEmitted, this);
|
||||
this.ticker.bgFrameEmitted.add(this.onBackgroundFrame, this);
|
||||
this.ticker.start();
|
||||
|
||||
window.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,20 @@
|
||||
export const CHANGELOG = [
|
||||
{
|
||||
version: "1.0.4",
|
||||
date: "26.05.2020",
|
||||
entries: [
|
||||
"<strong>Balancing</strong> Reduce cost of first painting upgrade, and change 'Shape Processing' to 'Cutting, Rotating & Stacking'",
|
||||
"<strong>Tutorial</strong> Add dialog after completing level 2 to check out the upgrades tab.",
|
||||
"<strong>Misc</strong> Allow changing the keybindings in the demo version",
|
||||
],
|
||||
},
|
||||
{
|
||||
version: "1.0.3",
|
||||
date: "24.05.2020",
|
||||
entries: [
|
||||
"<strong>Balancing</strong> Reduced the amount of shapes required for the first 5 levels to make it easier to get into the game.",
|
||||
],
|
||||
},
|
||||
{
|
||||
version: "1.0.2",
|
||||
date: "23.05.2020",
|
||||
|
@ -155,6 +155,7 @@ export class ClickDetector {
|
||||
* @param {Event} event
|
||||
*/
|
||||
internalPreventClick(event) {
|
||||
window.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
@ -301,6 +302,8 @@ export class ClickDetector {
|
||||
* @param {TouchEvent|MouseEvent} event
|
||||
*/
|
||||
internalOnPointerDown(event) {
|
||||
window.focus();
|
||||
|
||||
if (!this.internalEventPreHandler(event, 1)) {
|
||||
return false;
|
||||
}
|
||||
@ -369,6 +372,8 @@ export class ClickDetector {
|
||||
* @param {TouchEvent|MouseEvent} event
|
||||
*/
|
||||
internalOnPointerEnd(event) {
|
||||
window.focus();
|
||||
|
||||
if (!this.internalEventPreHandler(event, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -94,14 +94,15 @@ export const globalConfig = {
|
||||
// showChunkBorders: true,
|
||||
// rewardsInstant: true,
|
||||
// allBuildingsUnlocked: true,
|
||||
upgradesNoCost: true,
|
||||
// upgradesNoCost: true,
|
||||
// disableUnlockDialog: true,
|
||||
// disableLogicTicks: true,
|
||||
// testClipping: true,
|
||||
// framePausesBetweenTicks: 40,
|
||||
// testTranslations: true,
|
||||
// enableEntityInspector: true,
|
||||
testAds: true,
|
||||
// testAds: true,
|
||||
// disableMapOverview: true,
|
||||
/* dev:end */
|
||||
},
|
||||
|
||||
@ -123,3 +124,8 @@ export const IS_MOBILE = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
// Automatic calculations
|
||||
|
||||
globalConfig.minerSpeedItemsPerSecond = globalConfig.beltSpeedItemsPerSecond / 5;
|
||||
|
||||
if (globalConfig.debug.disableMapOverview) {
|
||||
globalConfig.mapChunkOverviewMinZoom = 0;
|
||||
globalConfig.mapChunkPrerenderMinZoom = 0;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ export class InputDistributor {
|
||||
// TAB
|
||||
event.keyCode === 9 ||
|
||||
// F1 - F10
|
||||
(event.keyCode >= 112 && event.keyCode < 122 && !G_IS_DEV)
|
||||
(event.keyCode >= 112 && event.keyCode < 122)
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ class LoaderImpl {
|
||||
|
||||
return Promise.race([
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(reject, G_IS_DEV ? 3000 : 60000);
|
||||
setTimeout(reject, G_IS_DEV ? 500 : 10000);
|
||||
}),
|
||||
|
||||
new Promise(resolve => {
|
||||
|
@ -3,13 +3,8 @@ const options = queryString.parse(location.search);
|
||||
|
||||
export let queryParamOptions = {
|
||||
embedProvider: null,
|
||||
betaMode: null,
|
||||
};
|
||||
|
||||
if (options.embed) {
|
||||
queryParamOptions.embedProvider = options.embed;
|
||||
}
|
||||
|
||||
if (!G_IS_RELEASE && options.betamode) {
|
||||
queryParamOptions.betaMode = true;
|
||||
}
|
||||
|
@ -715,10 +715,6 @@ export class Camera extends BasicSerializableObject {
|
||||
if (G_IS_DEV && globalConfig.debug.disableZoomLimits) {
|
||||
return;
|
||||
}
|
||||
if (queryParamOptions.betaMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = this.root.app.platformWrapper;
|
||||
|
||||
assert(Number.isFinite(this.zoomLevel), "Invalid zoom level *before* clamp: " + this.zoomLevel);
|
||||
|
@ -145,9 +145,6 @@ export class HubGoals extends BasicSerializableObject {
|
||||
if (G_IS_DEV && globalConfig.debug.allBuildingsUnlocked) {
|
||||
return true;
|
||||
}
|
||||
if (queryParamOptions.betaMode) {
|
||||
return true;
|
||||
}
|
||||
return !!this.gainedRewards[reward];
|
||||
}
|
||||
|
||||
@ -233,9 +230,6 @@ export class HubGoals extends BasicSerializableObject {
|
||||
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
||||
return true;
|
||||
}
|
||||
if (queryParamOptions.betaMode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const tierData = handle.tiers[currentLevel];
|
||||
|
||||
@ -282,8 +276,6 @@ export class HubGoals extends BasicSerializableObject {
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
||||
// Dont take resources
|
||||
} else if (queryParamOptions.betaMode) {
|
||||
// Same
|
||||
} else {
|
||||
for (let i = 0; i < tierData.required.length; ++i) {
|
||||
const requirement = tierData.required[i];
|
||||
|
@ -8,6 +8,7 @@ import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
|
||||
export class HUDUnlockNotification extends BaseHUDPart {
|
||||
initialize() {
|
||||
@ -25,6 +26,8 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
}
|
||||
|
||||
createElements(parent) {
|
||||
this.inputReciever = new InputReceiver("unlock-notification");
|
||||
|
||||
this.element = makeDiv(parent, "ingame_HUD_UnlockNotification", []);
|
||||
|
||||
const dialog = makeDiv(this.element, null, ["dialog"]);
|
||||
@ -47,6 +50,7 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
* @param {enumHubGoalRewards} reward
|
||||
*/
|
||||
showForLevel(level, reward) {
|
||||
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
||||
this.elemTitle.innerText = T.ingame.levelCompleteNotification.levelTitle.replace(
|
||||
"<level>",
|
||||
("" + level).padStart(2, "0")
|
||||
@ -92,6 +96,7 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
|
||||
if (this.buttonShowTimeout) {
|
||||
clearTimeout(this.buttonShowTimeout);
|
||||
this.buttonShowTimeout = null;
|
||||
@ -101,10 +106,19 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
requestClose() {
|
||||
this.root.app.adProvider.showVideoAd().then(() => {
|
||||
this.close();
|
||||
if (this.root.hubGoals.level === 3) {
|
||||
const { showUpgrades } = this.root.hud.parts.dialogs.showInfo(
|
||||
T.dialogs.upgradesIntroduction.title,
|
||||
T.dialogs.upgradesIntroduction.desc,
|
||||
["showUpgrades:good:timeout"]
|
||||
);
|
||||
showUpgrades.add(() => this.root.hud.parts.shop.show());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
|
||||
if (this.buttonShowTimeout) {
|
||||
clearTimeout(this.buttonShowTimeout);
|
||||
this.buttonShowTimeout = null;
|
||||
|
@ -30,20 +30,23 @@ export const enumHubGoalRewards = {
|
||||
};
|
||||
|
||||
export const tutorialGoals = [
|
||||
// 1
|
||||
// Circle
|
||||
{
|
||||
shape: "CuCuCuCu", // belts t1
|
||||
required: 60,
|
||||
required: 35,
|
||||
reward: enumHubGoalRewards.reward_cutter_and_trash,
|
||||
},
|
||||
|
||||
// 2
|
||||
// Cutter
|
||||
{
|
||||
shape: "----CuCu", //
|
||||
required: 80,
|
||||
required: 50,
|
||||
reward: enumHubGoalRewards.no_reward,
|
||||
},
|
||||
|
||||
// 3
|
||||
// Rectangle
|
||||
{
|
||||
shape: "RuRuRuRu", // miners t1
|
||||
@ -51,12 +54,14 @@ export const tutorialGoals = [
|
||||
reward: enumHubGoalRewards.reward_splitter,
|
||||
},
|
||||
|
||||
// 4
|
||||
{
|
||||
shape: "RuRu----", // processors t2
|
||||
required: 350,
|
||||
required: 150,
|
||||
reward: enumHubGoalRewards.reward_rotater,
|
||||
},
|
||||
|
||||
// 5
|
||||
// Rotater
|
||||
{
|
||||
shape: "Cu----Cu", // belts t2
|
||||
@ -64,25 +69,29 @@ export const tutorialGoals = [
|
||||
reward: enumHubGoalRewards.reward_tunnel,
|
||||
},
|
||||
|
||||
// 6
|
||||
{
|
||||
shape: "Cu------", // miners t2
|
||||
required: 1000,
|
||||
required: 700,
|
||||
reward: enumHubGoalRewards.reward_painter,
|
||||
},
|
||||
|
||||
// 7
|
||||
// Painter
|
||||
{
|
||||
shape: "CrCrCrCr", // unused
|
||||
required: 1500,
|
||||
required: 1300,
|
||||
reward: enumHubGoalRewards.reward_rotater_ccw,
|
||||
},
|
||||
|
||||
// 8
|
||||
{
|
||||
shape: "RbRb----", // painter t2
|
||||
required: 2500,
|
||||
reward: enumHubGoalRewards.reward_mixer,
|
||||
},
|
||||
|
||||
// 9
|
||||
// Mixing (purple)
|
||||
{
|
||||
shape: "CpCpCpCp", // belts t3
|
||||
@ -90,6 +99,7 @@ export const tutorialGoals = [
|
||||
reward: enumHubGoalRewards.reward_splitter_compact,
|
||||
},
|
||||
|
||||
// 10
|
||||
// Star shape + cyan
|
||||
{
|
||||
shape: "ScScScSc", // miners t3
|
||||
@ -97,6 +107,7 @@ export const tutorialGoals = [
|
||||
reward: enumHubGoalRewards.reward_stacker,
|
||||
},
|
||||
|
||||
// 11
|
||||
// Stacker
|
||||
{
|
||||
shape: "CgScScCg", // processors t3
|
||||
@ -104,36 +115,42 @@ export const tutorialGoals = [
|
||||
reward: enumHubGoalRewards.reward_miner_chainable,
|
||||
},
|
||||
|
||||
// 12
|
||||
{
|
||||
shape: "RpRpRpRp:CwCwCwCw", // painting t3
|
||||
required: 7000,
|
||||
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
||||
},
|
||||
|
||||
// 13
|
||||
{
|
||||
shape: "SrSrSrSr:CyCyCyCy", // unused
|
||||
required: 7850,
|
||||
reward: enumHubGoalRewards.reward_storage,
|
||||
},
|
||||
|
||||
// 14
|
||||
{
|
||||
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
|
||||
required: 8000,
|
||||
reward: enumHubGoalRewards.reward_cutter_quad,
|
||||
},
|
||||
|
||||
// 15
|
||||
{
|
||||
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
||||
required: 9000,
|
||||
reward: enumHubGoalRewards.reward_painter_double,
|
||||
},
|
||||
|
||||
// 16
|
||||
{
|
||||
shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two varinats)
|
||||
required: 10000,
|
||||
reward: enumHubGoalRewards.reward_painter_quad,
|
||||
},
|
||||
|
||||
// 17
|
||||
{
|
||||
shape: finalGameShape,
|
||||
required: 50000,
|
||||
|
@ -97,7 +97,7 @@ export const UPGRADES = {
|
||||
painting: {
|
||||
tiers: [
|
||||
{
|
||||
required: [{ shape: "WrWrWrWr", amount: 2000 }],
|
||||
required: [{ shape: "WrWrWrWr", amount: 500 }],
|
||||
improvement: 1,
|
||||
},
|
||||
{
|
||||
|
2
src/js/globals.d.ts
vendored
2
src/js/globals.d.ts
vendored
@ -107,8 +107,6 @@ declare interface Window {
|
||||
assert(condition: boolean, failureMessage: string);
|
||||
|
||||
coreThreadLoadedCb();
|
||||
|
||||
gameanalytics: typeof import("./game_analytics");
|
||||
}
|
||||
|
||||
declare interface Navigator {
|
||||
|
@ -137,7 +137,8 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
ingameTime: root.time.now(),
|
||||
category,
|
||||
value,
|
||||
gameDump: this.generateGameDump(root),
|
||||
version: G_BUILD_VERSION,
|
||||
gameDump: this.generateGameDump(root, category === "sync"),
|
||||
});
|
||||
}
|
||||
|
||||
@ -152,14 +153,15 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
/**
|
||||
* Generates a game dump
|
||||
* @param {GameRoot} root
|
||||
* @param {boolean=} metaOnly
|
||||
*/
|
||||
generateGameDump(root) {
|
||||
generateGameDump(root, metaOnly = false) {
|
||||
let staticEntities = [];
|
||||
|
||||
const entities = root.entityMgr.getAllWithComponent(StaticMapEntityComponent);
|
||||
|
||||
// Limit the entities
|
||||
if (entities.length < 5000) {
|
||||
if (!metaOnly && entities.length < 500) {
|
||||
for (let i = 0; i < entities.length; ++i) {
|
||||
const entity = entities[i];
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
|
@ -23,7 +23,7 @@ class SoundSpritesContainer {
|
||||
}
|
||||
return (this.loadingPromise = Promise.race([
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(reject, G_IS_DEV ? 5000 : 60000);
|
||||
setTimeout(reject, G_IS_DEV ? 500 : 5000);
|
||||
}),
|
||||
new Promise(resolve => {
|
||||
this.howl = new Howl({
|
||||
@ -100,7 +100,7 @@ class MusicInstance extends MusicInstanceInterface {
|
||||
load() {
|
||||
return Promise.race([
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(reject, G_IS_DEV ? 5000 : 60000);
|
||||
setTimeout(reject, G_IS_DEV ? 500 : 5000);
|
||||
}),
|
||||
new Promise((resolve, reject) => {
|
||||
this.howl = new Howl({
|
||||
|
@ -34,10 +34,12 @@ export class StorageImplBrowserIndexedDB extends StorageInterface {
|
||||
reject("Indexed DB access error");
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
request.onsuccess = event => resolve(event.target.result);
|
||||
|
||||
request.onupgradeneeded = /** @type {IDBVersionChangeEvent} */ event => {
|
||||
/** @type {IDBDatabase} */
|
||||
// @ts-ignore
|
||||
const database = event.target.result;
|
||||
|
||||
const objectStore = database.createObjectStore("files", {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Math_min } from "../../core/builtins";
|
||||
import { globalConfig, IS_MOBILE } from "../../core/config";
|
||||
import { globalConfig, IS_MOBILE, IS_DEBUG, IS_DEMO } from "../../core/config";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
import { clamp } from "../../core/utils";
|
||||
@ -19,6 +19,8 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||
iframed: false,
|
||||
externalLinks: true,
|
||||
iogLink: true,
|
||||
unlimitedSavegames: IS_DEMO ? false : true,
|
||||
showDemoBadge: IS_DEMO,
|
||||
};
|
||||
|
||||
if (!G_IS_STANDALONE && queryParamOptions.embedProvider) {
|
||||
@ -35,6 +37,8 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||
case "iogames.space": {
|
||||
this.embedProvider.id = "iogames.space";
|
||||
this.embedProvider.iogLink = true;
|
||||
this.embedProvider.unlimitedSavegames = true;
|
||||
this.embedProvider.showDemoBadge = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -71,6 +75,14 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||
return super.initialize().then(() => this.initializeAdProvider());
|
||||
}
|
||||
|
||||
getHasUnlimitedSavegames() {
|
||||
return this.embedProvider.unlimitedSavegames;
|
||||
}
|
||||
|
||||
getShowDemoBadges() {
|
||||
return this.embedProvider.showDemoBadge;
|
||||
}
|
||||
|
||||
onSentryLoaded() {
|
||||
logger.log("Initializing sentry");
|
||||
window.Sentry.init({
|
||||
|
@ -29,6 +29,17 @@ export class PlatformWrapperInterface {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user has unlimited savegames
|
||||
*/
|
||||
getHasUnlimitedSavegames() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getShowDemoBadges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the strength of touch pans with the mouse
|
||||
*/
|
||||
|
@ -26,7 +26,6 @@ export class BaseSavegameInterface {
|
||||
*/
|
||||
getSchemaUncached() {
|
||||
throw new Error("Implement get schema");
|
||||
return {};
|
||||
}
|
||||
|
||||
getValidator() {
|
||||
|
@ -82,10 +82,10 @@ export class KeybindingsState extends TextualGameState {
|
||||
}
|
||||
|
||||
editKeybinding(id) {
|
||||
if (IS_DEMO) {
|
||||
this.dialogs.showFeatureRestrictionInfo(T.demo.features.customizeKeybindings);
|
||||
return;
|
||||
}
|
||||
// if (IS_DEMO) {
|
||||
// this.dialogs.showFeatureRestrictionInfo(T.demo.features.customizeKeybindings);
|
||||
// return;
|
||||
// }
|
||||
|
||||
const dialog = new Dialog({
|
||||
app: this.app,
|
||||
|
@ -54,7 +54,11 @@ export class MainMenuState extends GameState {
|
||||
|
||||
<div class="logo">
|
||||
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
|
||||
${IS_DEMO ? `<div class="demoBadge"></div>` : ""}
|
||||
${
|
||||
IS_DEMO && this.app.platformWrapper.getShowDemoBadges()
|
||||
? `<div class="demoBadge"></div>`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@ -93,7 +97,7 @@ export class MainMenuState extends GameState {
|
||||
G_IS_BROWSER &&
|
||||
this.app.platformWrapper instanceof PlatformWrapperImplBrowser &&
|
||||
this.app.platformWrapper.embedProvider.iogLink
|
||||
? `<a class="iogLink" target="_blank" href="https://iogames.space">More .io games</a>`
|
||||
? `<a class="iogLink" target="_blank" href="https://iogames.space">.io games</a>`
|
||||
: ""
|
||||
}
|
||||
|
||||
@ -104,7 +108,11 @@ export class MainMenuState extends GameState {
|
||||
}
|
||||
|
||||
requestImportSavegame() {
|
||||
if (IS_DEMO && this.app.savegameMgr.getSavegamesMetaData().length > 0) {
|
||||
if (
|
||||
IS_DEMO &&
|
||||
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
||||
!this.app.platformWrapper.getHasUnlimitedSavegames()
|
||||
) {
|
||||
this.app.analytics.trackUiClick("importgame_slot_limit_show");
|
||||
this.dialogs.showWarning(T.dialogs.oneSavegameLimit.title, T.dialogs.oneSavegameLimit.desc);
|
||||
return;
|
||||
@ -122,6 +130,7 @@ export class MainMenuState extends GameState {
|
||||
const closeLoader = this.dialogs.showLoadingDialog();
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", event => {
|
||||
// @ts-ignore
|
||||
const contents = event.target.result;
|
||||
let realContent;
|
||||
|
||||
@ -372,7 +381,11 @@ export class MainMenuState extends GameState {
|
||||
}
|
||||
|
||||
onPlayButtonClicked() {
|
||||
if (IS_DEMO && this.app.savegameMgr.getSavegamesMetaData().length > 0) {
|
||||
if (
|
||||
IS_DEMO &&
|
||||
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
||||
!this.app.platformWrapper.getHasUnlimitedSavegames()
|
||||
) {
|
||||
this.app.analytics.trackUiClick("startgame_slot_limit_show");
|
||||
this.dialogs.showWarning(T.dialogs.oneSavegameLimit.title, T.dialogs.oneSavegameLimit.desc);
|
||||
return;
|
||||
|
@ -186,7 +186,8 @@ export class PreloadState extends GameState {
|
||||
return G_BUILD_VERSION;
|
||||
})
|
||||
.then(version => {
|
||||
this.app.storage.writeFileAsync("lastversion.bin", version);
|
||||
logger.log("Last version:", version, "App version:", G_BUILD_VERSION);
|
||||
this.app.storage.writeFileAsync("lastversion.bin", G_BUILD_VERSION);
|
||||
return version;
|
||||
})
|
||||
.then(version => {
|
||||
|
@ -89,6 +89,7 @@ dialogs:
|
||||
getStandalone: Get Standalone
|
||||
deleteGame: I know what I do
|
||||
viewUpdate: View Update
|
||||
showUpgrades: Show Upgrades
|
||||
|
||||
importSavegameError:
|
||||
title: Import Error
|
||||
@ -165,6 +166,12 @@ dialogs:
|
||||
desc: >-
|
||||
Whenever you need help or are stuck, check out the 'Show hint' button in the lower left and I'll give my best to help you!
|
||||
|
||||
upgradesIntroduction:
|
||||
title: Unlock Upgrades
|
||||
desc: >-
|
||||
All shapes you produce can be used to unlock upgrades - <strong>Don't destroy your old factories!</strong>
|
||||
The upgrades tab can be found on the top right corner of the screen.
|
||||
|
||||
ingame:
|
||||
# This is shown in the top left corner and displays useful keybindings in
|
||||
# every situation
|
||||
@ -277,7 +284,7 @@ shopUpgrades:
|
||||
name: Extraction
|
||||
description: Speed +<gain>%
|
||||
processors:
|
||||
name: Shape Processing
|
||||
name: Cutting, Rotating & Stacking
|
||||
description: Speed +<gain>%
|
||||
painting:
|
||||
name: Mixing & Painting
|
||||
@ -507,7 +514,7 @@ keybindings:
|
||||
resetKeybindings: Reset Keyinbindings
|
||||
|
||||
categoryLabels:
|
||||
general: Appplication
|
||||
general: Application
|
||||
ingame: Game
|
||||
placement: Placement
|
||||
massSelect: Mass Delete
|
||||
|
582
translations/base-fr.yaml
Normal file
582
translations/base-fr.yaml
Normal file
@ -0,0 +1,582 @@
|
||||
#
|
||||
# GAME TRANSLATIONS
|
||||
#
|
||||
# Contributing:
|
||||
#
|
||||
# If you want to contribute, please make a pull request on this respository
|
||||
# and I will have a look.
|
||||
#
|
||||
# Placeholders:
|
||||
#
|
||||
# Do *not* replace placeholders! Placeholders have a special syntax like
|
||||
# `Hotkey: <key>`. They are encapsulated within angle brackets. The correct
|
||||
# translation for this one in German for example would be: `Taste: <key>` (notice
|
||||
# how the placeholder stayed '<key>' and was not replaced!)
|
||||
#
|
||||
# Adding a new language:
|
||||
#
|
||||
# If you want to add a new language, ask me in the discord and I will setup
|
||||
# the basic structure so the game also detects it.
|
||||
#
|
||||
|
||||
global:
|
||||
loading: Chargement
|
||||
error: Erreur
|
||||
|
||||
# How big numbers are rendered, e.g. "10,000"
|
||||
thousandsDivider: "."
|
||||
|
||||
# Shown for infinitely big numbers
|
||||
infinite: inf
|
||||
|
||||
time:
|
||||
# Used for formatting past time dates
|
||||
oneSecondAgo: il y a une seconde
|
||||
xSecondsAgo: il y a <x> secondes
|
||||
oneMinuteAgo: il y a une minute
|
||||
xMinutesAgo: il y a <x> minutes
|
||||
oneHourAgo: il y a une heure
|
||||
xHoursAgo: il y a <x> heures
|
||||
oneDayAgo: il y a un jour
|
||||
xDaysAgo: il y a <x> jours
|
||||
|
||||
# Short formats for times, e.g. '5h 23m'
|
||||
secondsShort: <seconds>s
|
||||
minutesAndSecondsShort: <minutes>m <seconds>s
|
||||
hoursAndMinutesShort: <hours>h <minutes>s
|
||||
|
||||
xMinutes: <x> minutes
|
||||
|
||||
keys:
|
||||
tab: TAB
|
||||
control: CTRL
|
||||
alt: ALT
|
||||
escape: ESC
|
||||
shift: SHIFT
|
||||
space: ESPACE
|
||||
|
||||
demoBanners:
|
||||
# This is the "advertisement" shown in the main menu and other various places
|
||||
title: Salut!
|
||||
intro: >-
|
||||
Si vous appreciez ce jeu, merci de penser à acheter la version complète!
|
||||
advantages:
|
||||
- Pas de publicité
|
||||
- Sauvegardes illimitées
|
||||
- Mode sombre & plus
|
||||
- >-
|
||||
Donnez-moi l'opportunité de développer shapez.io ❤️
|
||||
|
||||
mainMenu:
|
||||
play: Jouer
|
||||
changelog: Historique
|
||||
importSavegame: Importer
|
||||
openSourceHint: Ce jeu est open source!
|
||||
discordLink: Serveur Discord officiel
|
||||
|
||||
# This is shown when using firefox and other browsers which are not supported.
|
||||
browserWarning: >-
|
||||
Désolé, mais ce jeu est connu pour tourner lentement sur votre browser! Procurez-vous la version autonome ou téléchargez Chrome pour une meilleure expérience.
|
||||
|
||||
dialogs:
|
||||
buttons:
|
||||
ok: OK
|
||||
delete: Effacer
|
||||
cancel: Annuler
|
||||
later: Plus tard
|
||||
restart: Relancer
|
||||
reset: Réinitialiser
|
||||
getStandalone: Se procurer la version autonome
|
||||
deleteGame: Je sais ce que je fais
|
||||
viewUpdate: Voir les mises-à-jour
|
||||
showUpgrades: Montrer les améliorations
|
||||
|
||||
importSavegameError:
|
||||
title: Erreur d'importation
|
||||
text: >-
|
||||
Impossible d'importer votre sauvegarde:
|
||||
|
||||
importSavegameSuccess:
|
||||
title: Sauvegarde importée
|
||||
text: >-
|
||||
Votre sauvegarde a été importée avec succès.
|
||||
|
||||
gameLoadFailure:
|
||||
title: Le jeu est cassé
|
||||
text: >-
|
||||
Impossible de charger votre sauvegarde:
|
||||
|
||||
confirmSavegameDelete:
|
||||
title: Confirmez la suppression
|
||||
text: >-
|
||||
Etes-vous certains de vouloir supprimer votre partie?
|
||||
|
||||
savegameDeletionError:
|
||||
title: Impossible de supprimer
|
||||
text: >-
|
||||
Impossible de supprimer votre sauvegarde:
|
||||
|
||||
restartRequired:
|
||||
title: Redémarrage requis
|
||||
text: >-
|
||||
Vous devez relancer le jeu pour appliquer les modifications.
|
||||
|
||||
editKeybinding:
|
||||
title: Changer les contrôles
|
||||
desc: Appuyez sur la touche que vous voulez assigner, ou Escape pour annuler.
|
||||
|
||||
resetKeybindingsConfirmation:
|
||||
title: Réinitialiser les contrôles
|
||||
desc: Ceci réinitialisera les touches par défaut. Veuillez confirmer.
|
||||
|
||||
keybindingsResetOk:
|
||||
title: Réinitialisation des contrôles
|
||||
desc: Les contrôles ont été réinitialisés par leur état par défaut respectifs!
|
||||
|
||||
featureRestriction:
|
||||
title: Version Démo
|
||||
desc: Vous avez essayé d'accéder à la fonction (<feature>) qui n'est pas disponible dans la démo. Considérez l'achat de la version complète pour une expérience optimale!
|
||||
|
||||
saveNotPossibleInDemo:
|
||||
desc: Votre partie a été sauvegardée, mais la charger n'est possible que dans la version complète. Considérez l'achat de la version complète pour une expérience optimale!
|
||||
|
||||
leaveNotPossibleInDemo:
|
||||
title: Version Démo
|
||||
desc: Votre partie a été sauvée mais nous ne pourrez pas la charger dans la démo. Charger les parties n'est disponible que dans la version complète. Etes-vous certain?
|
||||
|
||||
newUpdate:
|
||||
title: Mise-à-jour disponible
|
||||
desc: Une mise-à-jour est disponible pour ce jeu!
|
||||
|
||||
demoExplanation:
|
||||
title: Note du développeur
|
||||
desc: Je développe ce jeu pendant mon temps libre, et j'espère que vous l'appréciez! Si c'est le cas, merci de considérez l'achat de la version complète!
|
||||
|
||||
oneSavegameLimit:
|
||||
title: Sauvegardes limitées
|
||||
desc: Vous ne pouvez avoir qu'une seule sauvegarde en même temps dans la version démo. Merci de soit effacer l'actuelle ou de vous procurer la version complète!
|
||||
|
||||
updateSummary:
|
||||
title: Nouvel mise-à-jour!
|
||||
desc: >-
|
||||
Voici les modifications depuis votre dernière session:
|
||||
|
||||
hintDescription:
|
||||
title: Tutorial
|
||||
desc: >-
|
||||
Si vous avez besoin d'aide ou êtes coincé, vérifiez le bouton 'Aide' dans le coin inférieur gauche et j'essayerai de vous aider au mieux!
|
||||
|
||||
upgradesIntroduction:
|
||||
title: Débloquer les améliorations
|
||||
desc: >-
|
||||
Toutes les formes que vous produisez peuvent être utilisées pour débloquer des améliorations - <strong>Ne détruisez pas vos anciennes usines!</strong>
|
||||
L'onglet des améliorations se trouve dans le coin supérieur droit de l'écran.
|
||||
|
||||
ingame:
|
||||
# This is shown in the top left corner and displays useful keybindings in
|
||||
# every situation
|
||||
keybindingsOverlay:
|
||||
centerMap: Centrer
|
||||
moveMap: Déplacer
|
||||
removeBuildings: Effacer
|
||||
stopPlacement: Arrêter le placement
|
||||
rotateBuilding: Tourner le bâtiment
|
||||
placeMultiple: Placement multiple
|
||||
reverseOrientation: Changer l'orientation
|
||||
disableAutoOrientation: Désactiver l'orientation automatique
|
||||
toggleHud: Basculet l'ATH
|
||||
placeBuilding: Placer un bâtiment
|
||||
|
||||
# Everything related to placing buildings (I.e. as soon as you selected a building
|
||||
# from the toolbar)
|
||||
buildingPlacement:
|
||||
# Buildings can have different variants which are unlocked at later levels,
|
||||
# and this is the hint shown when there are multiple variants available.
|
||||
cycleBuildingVariants: Appuyez sur <key> pour changer de variante.
|
||||
|
||||
# Shows the hotkey in the ui, e.g. "Hotkey: Q"
|
||||
hotkeyLabel: >-
|
||||
Raccourci: <key>
|
||||
|
||||
infoTexts:
|
||||
speed: Vitesse
|
||||
range: Portée
|
||||
storage: Espace de stockage
|
||||
oneItemPerSecond: 1 forme / seconde
|
||||
itemsPerSecond: <x> formes / s
|
||||
itemsPerSecondDouble: (x2)
|
||||
|
||||
tiles: <x> cases
|
||||
|
||||
# The notification when completing a level
|
||||
levelCompleteNotification:
|
||||
# <level> is replaced by the actual level, so this gets 'Level 03' for example.
|
||||
levelTitle: Niveau <level>
|
||||
completed: Terminé
|
||||
unlockText: <reward> débloqué!
|
||||
buttonNextLevel: Niveau suivant
|
||||
|
||||
# Notifications on the lower right
|
||||
notifications:
|
||||
newUpgrade: Une nouvelle amélioration est disponible!
|
||||
gameSaved: Votre partie a été sauvegardée.
|
||||
|
||||
# Mass delete information, this is when you hold CTRL and then drag with your mouse
|
||||
# to select multiple buildings to delete
|
||||
massDelete:
|
||||
infoText: Appuyez sur <keyDelete> pour effacer les bâtiments sélectionnés et <keyCancel> pour annuler.
|
||||
|
||||
# The "Upgrades" window
|
||||
shop:
|
||||
title: Améliorations
|
||||
buttonUnlock: Améliorer
|
||||
|
||||
# Gets replaced to e.g. "Tier IX"
|
||||
tier: Echelon <x>
|
||||
|
||||
# The roman number for each tier
|
||||
tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X]
|
||||
|
||||
maximumLevel: Niveau maximum
|
||||
|
||||
# The "Statistics" window
|
||||
statistics:
|
||||
title: Statistiques
|
||||
dataSources:
|
||||
stored:
|
||||
title: Stocké
|
||||
description: Affiche le nombre de formes stockée dans votre bâtiment central.
|
||||
produced:
|
||||
title: Produit
|
||||
description: Affiche tous les formes que votre usine entière produit, en incluant les formes intermédiaires.
|
||||
delivered:
|
||||
title: Délivré
|
||||
description: Affiche les formes qui ont étés délivrées dans votres bâtiment central.
|
||||
noShapesProduced: Aucune forme n'a été produite jusqu'à présent.
|
||||
|
||||
# Displays the shapes per minute, e.g. '523 / m'
|
||||
shapesPerMinute: <shapes> / m
|
||||
|
||||
# Settings menu, when you press "ESC"
|
||||
settingsMenu:
|
||||
playtime: Temps de jeu
|
||||
|
||||
buildingsPlaced: Bâtiments
|
||||
beltsPlaced: Convoyeurs
|
||||
|
||||
buttons:
|
||||
continue: Continuer
|
||||
settings: Options
|
||||
menu: Retourner au menu
|
||||
|
||||
# Bottom left tutorial hints
|
||||
tutorialHints:
|
||||
title: Besoin d'aide?
|
||||
showHint: Indice
|
||||
hideHint: Fermer
|
||||
|
||||
# All shop upgrades
|
||||
shopUpgrades:
|
||||
belt:
|
||||
name: Convoyeurs, Distributeurs et Tunnels
|
||||
description: Vitesse +<gain>%
|
||||
miner:
|
||||
name: Extraction
|
||||
description: Vitesse +<gain>%
|
||||
processors:
|
||||
name: Découpage, Rotation et Empilage
|
||||
description: Vitesse +<gain>%
|
||||
painting:
|
||||
name: Mélange et Peinture
|
||||
description: Vitesse +<gain>%
|
||||
|
||||
# Buildings and their name / description
|
||||
buildings:
|
||||
belt:
|
||||
default:
|
||||
name: &belt Convoyeurs
|
||||
description: Transporte les objects, maintenez et fites glisser pour en placer plusieurs.
|
||||
|
||||
miner: # Internal name for the Extractor
|
||||
default:
|
||||
name: &miner Extracteurs
|
||||
description: Placez-le au dessus d'une forme ou couleur pour l'extraire.
|
||||
|
||||
chainable:
|
||||
name: Extracteur en série
|
||||
description: Placez-le au dessus d'une forme ou couleur pour l'extraire. Peut être mis en série.
|
||||
|
||||
underground_belt: # Internal name for the Tunnel
|
||||
default:
|
||||
name: &underground_belt Tunnel
|
||||
description: Permet de faire passer des ressources en dessous de bâtiment et convoyeurs.
|
||||
|
||||
tier2:
|
||||
name: Tunnel Echelon II
|
||||
description: Permet de faire passer des ressources en dessous de bâtiment et convoyeurs.
|
||||
|
||||
splitter: # Internal name for the Balancer
|
||||
default:
|
||||
name: &splitter Balancier
|
||||
description: Multifonctionnel - Distribue de manière égale toutes les entrées vers toutes les sorties.
|
||||
|
||||
compact:
|
||||
name: Fusionneur (compact)
|
||||
description: Fusionne deux convoyeurs en un.
|
||||
|
||||
compact-inverse:
|
||||
name: Fusionneur (compact)
|
||||
description: Fusionne deux convoyeurs en un.
|
||||
|
||||
cutter:
|
||||
default:
|
||||
name: &cutter Découpeur
|
||||
description: Coupe une forme de haut en bas et sort les deux parties. <strong>Si vous n'utilisez qu'une seule partie, assurez-vous de détruite l'autre ou cela coincera!</strong>
|
||||
quad:
|
||||
name: Découpeur (Quatre)
|
||||
description: Coupe une forme en 4 parts. <strong>Si vous n'utilisez qu'une seule partie, assurez-vous de détruite les autres ou cela coincera!</strong>
|
||||
|
||||
rotater:
|
||||
default:
|
||||
name: &rotater Pivoteur
|
||||
description: Fait pivoter une forme de 90 degrés vers la droite.
|
||||
ccw:
|
||||
name: Pivoteur inversé
|
||||
description: Fait pivoter une forme de 90 degrés vers la gauche.
|
||||
|
||||
stacker:
|
||||
default:
|
||||
name: &stacker Combineur
|
||||
description: Combine deux formes. Si elles ne peuvent pas êtres combinées, la forme de droite est placée sur la forme de gauche.
|
||||
|
||||
mixer:
|
||||
default:
|
||||
name: &mixer Mixeur de couleur
|
||||
description: Mixe deux couleurs en utilisant le mélange additif.
|
||||
|
||||
painter:
|
||||
default:
|
||||
name: &painter Peintre
|
||||
description: Colorie la forme entière de gauche avec la couleur de droite.
|
||||
double:
|
||||
name: Peintre (Double)
|
||||
description: Colorie les deux formes de gauche avec la couleur de droite.
|
||||
quad:
|
||||
name: Peintre (Quatre)
|
||||
description: Permet de colorier chaque quadrant d'une forme avec une couleur différente.
|
||||
|
||||
trash:
|
||||
default:
|
||||
name: &trash Poubelle
|
||||
description: Accepte des formes de n'importe quel côté et le détruit... pour toujours.
|
||||
|
||||
storage:
|
||||
name: Stockage
|
||||
description: Stocke les formes en trop jusqu'à une certaine capacité. Peut être utilisé comme tampon.
|
||||
|
||||
storyRewards:
|
||||
# Those are the rewards gained from completing the store
|
||||
reward_cutter_and_trash:
|
||||
title: Découper des formes
|
||||
desc: Vous venez de débloquer le <strong>découpeur</strong> - il coupe des formes en deux <strong>de haut en bas</strong> regardless of its orientation!<br><br>Be sure to get rid of the waste, or otherwise <strong>it will stall</strong> - A cet effet, je vous donne la poubelle, qui détruit tout ce que vous y mettez!
|
||||
|
||||
reward_rotater:
|
||||
title: Rotation
|
||||
desc: Le <strong>pivoteur</strong> a été débloqué! Il pivote les formes de 90 degrés vers la droite.
|
||||
|
||||
reward_painter:
|
||||
title: Peintre
|
||||
desc: >-
|
||||
Le <strong>peintre</strong> a été débloqué - Extrayez des pigments de couleur (comme vous le faites avec les formes) et combinez les avec une forme dans un peintre pour les colorier!<br><br>PS: Si vous êtes daltonien, je travaille déjà sur une solution!
|
||||
|
||||
reward_mixer:
|
||||
title: Mixeur de couleurs
|
||||
desc: Le <strong>mixeur</strong> a été débloqué - Combinez deux couleurs en utilisant <strong>le mélange additif</strong> avec ce bâtiment!
|
||||
|
||||
reward_stacker:
|
||||
title: Combineur
|
||||
desc: Vous pouvez maintenant combiner deux formes avec le <strong>combineur</strong>! Les deux entrées sont combinée et si elles peuvent êtres mises l'une à cpôté de l'autre, elles sont <strong>fusionnées</strong>. Sinon, la forme de droite est <strong>placée au dessus</strong> de la forme de gauche.
|
||||
|
||||
reward_splitter:
|
||||
title: Découpeur/Fusionneur
|
||||
desc: Le <strong>balancier</strong> multifonctionnel a été débloqué - Il peut être utilisé pour construire de plus grandes usines en <strong>découpant et fusionnant les formes</strong> sur plusieurs convoyeurs!<br><br>
|
||||
|
||||
reward_tunnel:
|
||||
title: Tunnel
|
||||
desc: Le <strong>tunnel</strong> a été débloqué - Vous pouvez maintenant faire passer des formes vous les convoyeurs et les bâtimentts avec ça!
|
||||
|
||||
reward_rotater_ccw:
|
||||
title: Pivoteur inversé
|
||||
desc: Vous avez débloqué une variante du <strong>pivoteur</strong> - Elle permet de faire pivoter vers la gauche! Pour le construite, sélectionnez le pivoteur et <strong>appuyez sur 'T' pour changer sa variante</strong>!
|
||||
|
||||
reward_miner_chainable:
|
||||
title: Extracteur en série
|
||||
desc: Vous avez débloqué <strong>l'extracteur en série</strong>! Il permet <strong>de transférer ses resources</strong> à d'autres extracteurs pour extraire les ressources plus efficacement!
|
||||
|
||||
reward_underground_belt_tier_2:
|
||||
title: Tunnel échelon II
|
||||
desc: Vous avez débloqué une nouvelle variante du <strong>tunnel</strong> - Elle a <strong>une portée plus grande</strong>, et vous pouvez également mixer ces tunnels maintenant!
|
||||
|
||||
reward_splitter_compact:
|
||||
title: Balancier compacte
|
||||
desc: >-
|
||||
Vous avez débloqué une variante compacte du <strong>balancier</strong> - Elle accepte deux entrées et les rassemble en une sortie!
|
||||
|
||||
reward_cutter_quad:
|
||||
title: Quadruple découpeur
|
||||
desc: Vous avez débloqué une variante du <strong>découpeur</strong> - Elle permet de de découper les formes en <strong>quatres parties</strong> à la place de simplement deux!
|
||||
|
||||
reward_painter_double:
|
||||
title: Double peintre
|
||||
desc: Vous avez débloqué une variante du <strong>peintre</strong> - Elle fonctionne comme le peintre de base, mais elle permet de traiter <strong>deux formes à la fois</strong> en ne consommant qu'une couleur au lieu de deux!
|
||||
|
||||
reward_painter_quad:
|
||||
title: Quadruple peintre
|
||||
desc: Vous avez débloqué une variante du <strong>peintre</strong> - Elle permet de colorier chaque partie d'une forme individuellement!
|
||||
|
||||
reward_storage:
|
||||
title: Tampon de stockage
|
||||
desc: Vous avez débloqué une variante de <strong>la poubelle</strong> - Elle permet de stocker des formes jusqu'à une certaine limite!
|
||||
|
||||
reward_freeplay:
|
||||
title: Mode libre
|
||||
desc: Vous l'avez fait! Vous avez débloqué le <strong>mode libre</strong>! Cela veut dire que dorénavant, les formes sont générées aléatoirement! (Ne vous en faites pas, plus de contenu est prévu pour la version complète!)
|
||||
|
||||
# Special reward, which is shown when there is no reward actually
|
||||
no_reward:
|
||||
title: Niveau suivant
|
||||
desc: >-
|
||||
Ce niveau n'a pas de récompense, mais le prochain oui! <br><br> PS: Vous ne devriez pas détruires votre usine actuelle - Vous aurez besoin de <strong>toutes</strong> ces formes plus tard pour <strong>débloquer les améliorations</strong>!
|
||||
|
||||
no_reward_freeplay:
|
||||
title: Niveau suivant
|
||||
desc: >-
|
||||
Bravo! D'ailleurs, plus de contenu est prévu pour la version complète!
|
||||
|
||||
settings:
|
||||
title: Options
|
||||
categories:
|
||||
game: Jeu
|
||||
app: Application
|
||||
|
||||
versionBadges:
|
||||
dev: Developpement
|
||||
staging: Test
|
||||
prod: Production
|
||||
buildDate: Créé le <at-date>
|
||||
|
||||
labels:
|
||||
uiScale:
|
||||
title: Taille de l'interface
|
||||
description: >-
|
||||
Change la taille de l'interface utilisateur. Cette interface se redimensionnera suivant la résolution de votre appareil, mais cette option contrôle le facteur de résolution.
|
||||
|
||||
fullscreen:
|
||||
title: Plein écran
|
||||
description: >-
|
||||
Il est recommandé de jouer au jeu en plein écran pour obtenir la meilleur expérience possible. Seulement disponible dans la version complète.
|
||||
|
||||
soundsMuted:
|
||||
title: Sons désactivés
|
||||
description: >-
|
||||
Si coché, tous les sons seront désactivés.
|
||||
|
||||
musicMuted:
|
||||
title: Musique désactivée
|
||||
description: >-
|
||||
Si coché, toute la musique sera désactivée.
|
||||
|
||||
theme:
|
||||
title: Thème
|
||||
description: >-
|
||||
Choisissez votre thème (clair / sombre).
|
||||
|
||||
refreshRate:
|
||||
title: Simulation Target
|
||||
description: >-
|
||||
Si vous avez un moniteur à 144hz, changez le taux de rafraichissement ici pour que le jeu fonctionne correctement à cette haute fréquence. Ceci pourrait diminuer vos IPS si votre ordinateur est trop lent.
|
||||
|
||||
alwaysMultiplace:
|
||||
title: Placement multiple
|
||||
description: >-
|
||||
Si activé, tous les bâtiments resterons sélectionnés tant que vous n'avez pas annulé. Ceci revient à garder la touche SHIFT appuyée en permanence.
|
||||
|
||||
offerHints:
|
||||
title: Indices
|
||||
description: >-
|
||||
ffiche ou non le bouton 'Afficher un indice' dans le coin inférieir gauche.
|
||||
|
||||
keybindings:
|
||||
title: Contrôles
|
||||
hint: >-
|
||||
Astuce: Soyez sûr d'utiliser CTRL, SHIFT et ALT! Ces touches activent différentes options de placement.
|
||||
|
||||
resetKeybindings: Réinitialiser les contrôles
|
||||
|
||||
categoryLabels:
|
||||
general: Application
|
||||
ingame: Jeu
|
||||
placement: Placement
|
||||
massSelect: Suppression de masse
|
||||
buildings: Raccourcis bâtiment
|
||||
placementModifiers: Modificateurs de placement
|
||||
|
||||
mappings:
|
||||
confirm: Confirmer
|
||||
back: Retour
|
||||
mapMoveUp: Aller en haut
|
||||
mapMoveRight: Aller à droite
|
||||
mapMoveDown: Aller en bas
|
||||
mapMoveLeft: Aller à gauche
|
||||
|
||||
centerMap: Centrer la carte
|
||||
|
||||
mapZoomIn: Zoom avant
|
||||
mapZoomOut: Zoom arrière
|
||||
|
||||
menuOpenShop: Améliorations
|
||||
menuOpenStats: Statistiques
|
||||
|
||||
toggleHud: Basculer l'ATH
|
||||
toggleFPSInfo: Basculer IPS et informations débogage
|
||||
belt: *belt
|
||||
splitter: *splitter
|
||||
underground_belt: *underground_belt
|
||||
miner: *miner
|
||||
cutter: *cutter
|
||||
rotater: *rotater
|
||||
stacker: *stacker
|
||||
mixer: *mixer
|
||||
painter: *painter
|
||||
trash: *trash
|
||||
|
||||
abortBuildingPlacement: Annuler le placement
|
||||
rotateWhilePlacing: Pivoter
|
||||
cycleBuildingVariants: Faire défiler les variantes
|
||||
confirmMassDelete: Confirmer la suppression de masse
|
||||
cycleBuildings: Faire défiler les bâtiments
|
||||
|
||||
massSelectStart: Cliquez et maintenez pour commencer
|
||||
massSelectSelectMultiple: Séléctionner plusieurs zones
|
||||
|
||||
placementDisableAutoOrientation: Désactiver l'orientation automatique
|
||||
placeMultiple: Rester en mode placement
|
||||
placeInverse: Inverser le mode d'orientation automatique
|
||||
|
||||
about:
|
||||
title: A propos de ce jeu
|
||||
|
||||
changelog:
|
||||
title: Historique
|
||||
|
||||
demo:
|
||||
features:
|
||||
restoringGames: Charger des sauvegardes
|
||||
importingGames: Importer des sauvegardes
|
||||
oneGameLimit: Limité à une sauvegarde
|
||||
customizeKeybindings: Personalisation des contrôles
|
||||
|
||||
settingNotAvailable: Indisponible dans la démo.
|
||||
|
||||
#
|
||||
# French translation version v0.1 based on english v1.0.4 by Didier WEERTS 'The Corsaire'
|
Loading…
Reference in New Issue
Block a user