mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-16 11:41:50 +00:00
Merge dfe90426ce into a7a2aad2b6
This commit is contained in:
commit
35aba7606a
@ -214,6 +214,35 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
> * {
|
||||
@include S(margin-right, 7.5px);
|
||||
}
|
||||
}
|
||||
|
||||
.detailsFormElem {
|
||||
> .object {
|
||||
pointer-events: all;
|
||||
|
||||
> summary {
|
||||
transition: opacity 0.1s ease-in-out;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
> div {
|
||||
@include S(margin-left, 4px);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .buttons {
|
||||
|
||||
@ -47,13 +47,67 @@ export class FormElement {
|
||||
}
|
||||
}
|
||||
|
||||
export class FormElementDetails extends FormElement {
|
||||
/**
|
||||
*
|
||||
* @param {object} param0
|
||||
* @param {string} param0.id
|
||||
* @param {string} param0.label
|
||||
* @param {Array<FormElement>} param0.formElements
|
||||
*/
|
||||
constructor({ id, label, formElements }) {
|
||||
super(id, label);
|
||||
this.formElements = formElements;
|
||||
|
||||
this.element = null;
|
||||
}
|
||||
|
||||
getHtml() {
|
||||
return `<div class="formElement detailsFormElem"><details class='object'>
|
||||
${this.label ? `<summary>${this.label}</summary>` : ""}
|
||||
<div class="content">
|
||||
${this.formElements.map(e => e.getHtml()).join("")}
|
||||
</div></details></div>`;
|
||||
}
|
||||
|
||||
bindEvents(parent, clickTrackers) {
|
||||
this.element = this.getFormElement(parent);
|
||||
|
||||
for (let i = 0; i < this.formElements.length; ++i) {
|
||||
const elem = this.formElements[i];
|
||||
elem.bindEvents(parent, clickTrackers);
|
||||
elem.valueChosen.add(this.valueChosen.dispatch, this.valueChosen);
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
let formElementValues = {};
|
||||
for (let i = 0; i < this.formElements.length; ++i) {
|
||||
const elem = this.formElements[i];
|
||||
formElementValues[elem.id] = elem.getValue();
|
||||
}
|
||||
return formElementValues;
|
||||
}
|
||||
|
||||
focus() {}
|
||||
}
|
||||
|
||||
export class FormElementInput extends FormElement {
|
||||
constructor({ id, label = null, placeholder, defaultValue = "", inputType = "text", validator = null }) {
|
||||
constructor({
|
||||
id,
|
||||
label = null,
|
||||
placeholder,
|
||||
defaultValue = "",
|
||||
inputType = "text",
|
||||
validator = null,
|
||||
inline = false,
|
||||
}) {
|
||||
super(id, label);
|
||||
this.placeholder = placeholder;
|
||||
this.defaultValue = defaultValue;
|
||||
this.inputType = inputType;
|
||||
this.validator = validator;
|
||||
this.inline = inline;
|
||||
|
||||
this.element = null;
|
||||
}
|
||||
@ -83,7 +137,7 @@ export class FormElementInput extends FormElement {
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="formElement input">
|
||||
<div class="formElement input ${this.inline ? "inline" : ""}">
|
||||
${this.label ? `<label>${this.label}</label>` : ""}
|
||||
<input
|
||||
type="${inputType}"
|
||||
@ -143,17 +197,18 @@ export class FormElementInput extends FormElement {
|
||||
}
|
||||
|
||||
export class FormElementCheckbox extends FormElement {
|
||||
constructor({ id, label, defaultValue = true }) {
|
||||
constructor({ id, label, defaultValue = true, inline = false }) {
|
||||
super(id, label);
|
||||
this.defaultValue = defaultValue;
|
||||
this.value = this.defaultValue;
|
||||
this.inline = inline;
|
||||
|
||||
this.element = null;
|
||||
}
|
||||
|
||||
getHtml() {
|
||||
return `
|
||||
<div class="formElement checkBoxFormElem">
|
||||
<div class="formElement checkBoxFormElem ${this.inline ? "inline" : ""}">
|
||||
${this.label ? `<label>${this.label}</label>` : ""}
|
||||
<div class="checkbox ${this.defaultValue ? "checked" : ""}" data-formId='${this.id}'>
|
||||
<span class="knob"></span>
|
||||
@ -181,7 +236,7 @@ export class FormElementCheckbox extends FormElement {
|
||||
this.element.classList.toggle("checked", this.value);
|
||||
}
|
||||
|
||||
focus(parent) {}
|
||||
focus() {}
|
||||
}
|
||||
|
||||
export class FormElementItemChooser extends FormElement {
|
||||
|
||||
@ -166,11 +166,22 @@ export class GameCore {
|
||||
/**
|
||||
* Initializes a new game, this means creating a new map and centering on the
|
||||
* playerbase
|
||||
*
|
||||
* @param {object} param1
|
||||
* @param {number} param1.seed
|
||||
* @param {boolean} param1.allowNonPrimaryColors
|
||||
* @param {number} param1.fullShapePercentage
|
||||
* @param {number} param1.wierdShapePercentage
|
||||
* */
|
||||
initNewGame() {
|
||||
initNewGame({ seed, allowNonPrimaryColors, fullShapePercentage, wierdShapePercentage }) {
|
||||
logger.log("Initializing new game");
|
||||
this.root.gameIsFresh = true;
|
||||
this.root.map.seed = randomInt(0, 100000);
|
||||
this.root.map.seed = seed;
|
||||
this.root.map.allowNonPrimaryColors = allowNonPrimaryColors;
|
||||
this.root.map.fullShapePercentage = fullShapePercentage;
|
||||
this.root.map.wierdShapePercentage = wierdShapePercentage;
|
||||
|
||||
logger.log("Initializing newGame with seed: ", this.root.map.seed);
|
||||
|
||||
if (!this.root.gameMode.hasHub()) {
|
||||
return;
|
||||
@ -208,6 +219,7 @@ export class GameCore {
|
||||
return false;
|
||||
}
|
||||
this.root.gameIsFresh = false;
|
||||
logger.log("Initializing existingGame with seed: ", this.root.map.seed);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,9 @@ export class BaseMap extends BasicSerializableObject {
|
||||
static getSchema() {
|
||||
return {
|
||||
seed: types.uint,
|
||||
allowNonPrimaryColors: types.bool,
|
||||
fullShapePercentage: types.uint,
|
||||
wierdShapePercentage: types.uint,
|
||||
};
|
||||
}
|
||||
|
||||
@ -27,6 +30,9 @@ export class BaseMap extends BasicSerializableObject {
|
||||
this.root = root;
|
||||
|
||||
this.seed = 0;
|
||||
this.allowNonPrimaryColors = false;
|
||||
this.fullShapePercentage = 0;
|
||||
this.wierdShapePercentage = 0;
|
||||
|
||||
/**
|
||||
* Mapping of 'X|Y' to chunk
|
||||
|
||||
@ -168,6 +168,11 @@ export class MapChunk {
|
||||
let availableColors = [enumColors.red, enumColors.green];
|
||||
if (distanceToOriginInChunks > 2) {
|
||||
availableColors.push(enumColors.blue);
|
||||
if (this.root.map.allowNonPrimaryColors) {
|
||||
availableColors.push(enumColors.yellow);
|
||||
availableColors.push(enumColors.purple);
|
||||
availableColors.push(enumColors.cyan);
|
||||
}
|
||||
}
|
||||
this.internalGeneratePatch(rng, colorPatchSize, COLOR_ITEM_SINGLETONS[rng.choice(availableColors)]);
|
||||
}
|
||||
@ -198,7 +203,19 @@ export class MapChunk {
|
||||
weights[enumSubShape.windmill] = 0;
|
||||
}
|
||||
|
||||
if (distanceToOriginInChunks < 10) {
|
||||
if (rng.nextRange(0, 100) <= this.root.map.fullShapePercentage) {
|
||||
// Spawn full shape based on percentage.
|
||||
const subShape = this.internalGenerateRandomSubShape(rng, weights);
|
||||
subShapes = [subShape, subShape, subShape, subShape];
|
||||
} else if (rng.nextRange(0, 100) <= this.root.map.wierdShapePercentage) {
|
||||
// Spawn wierd shape based on percentage.
|
||||
subShapes = [
|
||||
this.internalGenerateRandomSubShape(rng, weights),
|
||||
this.internalGenerateRandomSubShape(rng, weights),
|
||||
this.internalGenerateRandomSubShape(rng, weights),
|
||||
this.internalGenerateRandomSubShape(rng, weights),
|
||||
];
|
||||
} else if (distanceToOriginInChunks < 10) {
|
||||
// Initial chunk patches always have the same shape
|
||||
const subShape = this.internalGenerateRandomSubShape(rng, weights);
|
||||
subShapes = [subShape, subShape, subShape, subShape];
|
||||
|
||||
@ -28,7 +28,10 @@
|
||||
"shape": "#5d5f6a",
|
||||
"red": "#854f56",
|
||||
"green": "#667964",
|
||||
"blue": "#5e7ca4"
|
||||
"blue": "#5e7ca4",
|
||||
"purple": "#8776bc",
|
||||
"yellow": "#cab57d",
|
||||
"cyan": "#00b5b8"
|
||||
},
|
||||
"chunkOverview": {
|
||||
"empty": "#444856",
|
||||
|
||||
@ -28,7 +28,10 @@
|
||||
"shape": "#eaebec",
|
||||
"red": "#ffbfc1",
|
||||
"green": "#cbffc4",
|
||||
"blue": "#bfdaff"
|
||||
"blue": "#bfdaff",
|
||||
"purple": "#ecb3fc",
|
||||
"yellow": "#fcf99c",
|
||||
"cyan": "#85fdff"
|
||||
},
|
||||
|
||||
"chunkOverview": {
|
||||
|
||||
@ -14,6 +14,7 @@ import { SavegameInterface_V1006 } from "./schemas/1006";
|
||||
import { SavegameInterface_V1007 } from "./schemas/1007";
|
||||
import { SavegameInterface_V1008 } from "./schemas/1008";
|
||||
import { SavegameInterface_V1009 } from "./schemas/1009";
|
||||
import { SavegameInterface_V1010 } from "./schemas/1010";
|
||||
|
||||
const logger = createLogger("savegame");
|
||||
|
||||
@ -54,7 +55,7 @@ export class Savegame extends ReadWriteProxy {
|
||||
* @returns {number}
|
||||
*/
|
||||
static getCurrentVersion() {
|
||||
return 1009;
|
||||
return 1010;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,6 +161,11 @@ export class Savegame extends ReadWriteProxy {
|
||||
data.version = 1009;
|
||||
}
|
||||
|
||||
if (data.version === 1009) {
|
||||
SavegameInterface_V1010.migrate1009to1010(data);
|
||||
data.version = 1010;
|
||||
}
|
||||
|
||||
return ExplainedResult.good();
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import { SavegameInterface_V1006 } from "./schemas/1006";
|
||||
import { SavegameInterface_V1007 } from "./schemas/1007";
|
||||
import { SavegameInterface_V1008 } from "./schemas/1008";
|
||||
import { SavegameInterface_V1009 } from "./schemas/1009";
|
||||
import { SavegameInterface_V1010 } from "./schemas/1010";
|
||||
|
||||
/** @type {Object.<number, typeof BaseSavegameInterface>} */
|
||||
export const savegameInterfaces = {
|
||||
@ -23,6 +24,7 @@ export const savegameInterfaces = {
|
||||
1007: SavegameInterface_V1007,
|
||||
1008: SavegameInterface_V1008,
|
||||
1009: SavegameInterface_V1009,
|
||||
1010: SavegameInterface_V1010,
|
||||
};
|
||||
|
||||
const logger = createLogger("savegame_interface_registry");
|
||||
|
||||
38
src/js/savegame/schemas/1010.js
Normal file
38
src/js/savegame/schemas/1010.js
Normal file
@ -0,0 +1,38 @@
|
||||
import { createLogger } from "../../core/logging.js";
|
||||
import { SavegameInterface_V1009 } from "./1009.js";
|
||||
|
||||
const schema = require("./1010.json");
|
||||
const logger = createLogger("savegame_interface/1010");
|
||||
|
||||
export class SavegameInterface_V1010 extends SavegameInterface_V1009 {
|
||||
getVersion() {
|
||||
return 1010;
|
||||
}
|
||||
|
||||
getSchemaUncached() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../savegame_typedefs.js").SavegameData} data
|
||||
*/
|
||||
static migrate1009to1010(data) {
|
||||
logger.log("Migrating 1009 to 1010");
|
||||
const dump = data.dump;
|
||||
if (!dump) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!dump.map.hasOwnProperty("allowNonPrimaryColors")) {
|
||||
dump.map.allowNonPrimaryColors = false;
|
||||
}
|
||||
|
||||
if (!dump.map.hasOwnProperty("fullShapePercentage")) {
|
||||
dump.map.fullShapePercentage = 0;
|
||||
}
|
||||
|
||||
if (!dump.map.hasOwnProperty("wierdShapePercentage")) {
|
||||
dump.map.wierdShapePercentage = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
5
src/js/savegame/schemas/1010.json
Normal file
5
src/js/savegame/schemas/1010.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"additionalProperties": true
|
||||
}
|
||||
@ -48,6 +48,18 @@ export class GameCreationPayload {
|
||||
|
||||
/** @type {object|undefined} */
|
||||
this.gameModeParameters;
|
||||
|
||||
/** @type {number} */
|
||||
this.seed;
|
||||
|
||||
/** @type {boolean} */
|
||||
this.allowNonPrimaryColors;
|
||||
|
||||
/** @type {number} */
|
||||
this.fullShapePercentage;
|
||||
|
||||
/** @type {number} */
|
||||
this.wierdShapePercentage;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +85,18 @@ export class InGameState extends GameState {
|
||||
/** @type {Savegame} */
|
||||
this.savegame = null;
|
||||
|
||||
/** @type {number} */
|
||||
this.seed = null;
|
||||
|
||||
/** @type {boolean} */
|
||||
this.allowNonPrimaryColors = null;
|
||||
|
||||
/** @type {number} */
|
||||
this.fullShapePercentage = null;
|
||||
|
||||
/** @type {number} */
|
||||
this.wierdShapePercentage = null;
|
||||
|
||||
this.boundInputFilter = this.filterInput.bind(this);
|
||||
|
||||
/**
|
||||
@ -250,7 +274,12 @@ export class InGameState extends GameState {
|
||||
*/
|
||||
stage4aInitEmptyGame() {
|
||||
if (this.switchStage(stages.s4_A_initEmptyGame)) {
|
||||
this.core.initNewGame();
|
||||
this.core.initNewGame({
|
||||
seed: this.seed,
|
||||
allowNonPrimaryColors: this.allowNonPrimaryColors,
|
||||
fullShapePercentage: this.fullShapePercentage,
|
||||
wierdShapePercentage: this.wierdShapePercentage,
|
||||
});
|
||||
this.stage5FirstUpdate();
|
||||
}
|
||||
}
|
||||
@ -369,6 +398,10 @@ export class InGameState extends GameState {
|
||||
this.creationPayload = payload;
|
||||
this.savegame = payload.savegame;
|
||||
this.gameModeId = payload.gameModeId;
|
||||
this.seed = payload.seed;
|
||||
this.allowNonPrimaryColors = payload.allowNonPrimaryColors;
|
||||
this.fullShapePercentage = payload.fullShapePercentage;
|
||||
this.wierdShapePercentage = payload.wierdShapePercentage;
|
||||
|
||||
this.loadingOverlay = new GameLoadingOverlay(this.app, this.getDivElement());
|
||||
this.loadingOverlay.showBasic();
|
||||
|
||||
@ -3,7 +3,7 @@ import { cachebust } from "../core/cachebust";
|
||||
import { A_B_TESTING_LINK_TYPE, globalConfig, THIRDPARTY_URLS } from "../core/config";
|
||||
import { GameState } from "../core/game_state";
|
||||
import { DialogWithForm } from "../core/modal_dialog_elements";
|
||||
import { FormElementInput } from "../core/modal_dialog_forms";
|
||||
import { FormElementCheckbox, FormElementDetails, FormElementInput } from "../core/modal_dialog_forms";
|
||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||
import {
|
||||
formatSecondsToTimeAgo,
|
||||
@ -12,6 +12,7 @@ import {
|
||||
makeButton,
|
||||
makeButtonElement,
|
||||
makeDiv,
|
||||
randomInt,
|
||||
removeAllChildren,
|
||||
startFileChoose,
|
||||
waitNextFrame,
|
||||
@ -672,15 +673,97 @@ export class MainMenuState extends GameState {
|
||||
return;
|
||||
}
|
||||
|
||||
const regex = /^[a-zA-Z0-9_\- ]{1,20}$/;
|
||||
|
||||
const nameInput = new FormElementInput({
|
||||
id: "nameInput",
|
||||
// @TODO: Add translation (T.dialogs.newSavegame.nameInputLabel)
|
||||
label: "Name:",
|
||||
placeholder: "",
|
||||
defaultValue: "Unnamed",
|
||||
validator: val => val.match(regex) && trim(val).length > 0,
|
||||
inline: true,
|
||||
});
|
||||
|
||||
const seedInput = new FormElementInput({
|
||||
id: "seedInput",
|
||||
// @TODO: Add translation (T.dialogs.newSavegame.seedInputLabel)
|
||||
label: "Seed:",
|
||||
placeholder: "",
|
||||
defaultValue: randomInt(0, 100000).toString(),
|
||||
validator: val => Number.isInteger(Number(val)) && Number(val) >= 0 && Number(val) <= 100000,
|
||||
inline: true,
|
||||
});
|
||||
|
||||
const allowColorsCheckbox = new FormElementCheckbox({
|
||||
id: "allowColorsCheckbox",
|
||||
// @TODO: Add translation (T.dialogs.newSavegame.allowColorsCheckboxLabel)
|
||||
label: "Allow non-primarycolors: ",
|
||||
defaultValue: false,
|
||||
inline: true,
|
||||
});
|
||||
|
||||
const fullShapePercentageInput = new FormElementInput({
|
||||
id: "fullShapePercentageInput",
|
||||
label: "fullShape %:",
|
||||
placeholder: "",
|
||||
defaultValue: Number(0).toString(),
|
||||
validator: val => Number.isInteger(Number(val)) && Number(val) >= 0 && Number(val) <= 100,
|
||||
inline: true,
|
||||
});
|
||||
|
||||
const wierdShapePercentageInput = new FormElementInput({
|
||||
id: "wierdShapePercentageInput",
|
||||
label: "wierdShape %:",
|
||||
placeholder: "",
|
||||
defaultValue: Number(0).toString(),
|
||||
validator: val => Number.isInteger(Number(val)) && Number(val) >= 0 && Number(val) <= 100,
|
||||
inline: true,
|
||||
});
|
||||
|
||||
const advancedContainer = new FormElementDetails({
|
||||
id: "advancedContainer",
|
||||
// @TODO Add translation (T.dialogs.newSavegame.advanced)
|
||||
label: "Advanced Options",
|
||||
formElements: [
|
||||
seedInput,
|
||||
allowColorsCheckbox,
|
||||
fullShapePercentageInput,
|
||||
wierdShapePercentageInput,
|
||||
],
|
||||
});
|
||||
|
||||
const dialog = new DialogWithForm({
|
||||
app: this.app,
|
||||
// @TODO: Add translation (T.dialogs.newSavegame.title)
|
||||
title: "New Game Options",
|
||||
// @TODO: Add translation (T.dialogs.newSavegame.desc)
|
||||
desc: "Configure your new savegame",
|
||||
formElements: [nameInput, advancedContainer],
|
||||
buttons: ["ok:good:enter"],
|
||||
});
|
||||
this.dialogs.internalShowDialog(dialog);
|
||||
|
||||
dialog.buttonSignals.ok.add(() => {
|
||||
this.app.analytics.trackUiClick("startgame");
|
||||
this.app.adProvider.showVideoAd().then(() => {
|
||||
this.app.adProvider.showVideoAd().then(async () => {
|
||||
const savegame = this.app.savegameMgr.createNewSavegame();
|
||||
const savegameMetadata = this.app.savegameMgr.getGameMetaDataByInternalId(
|
||||
savegame.internalId
|
||||
);
|
||||
savegameMetadata.name = trim(nameInput.getValue());
|
||||
await this.app.savegameMgr.writeAsync();
|
||||
|
||||
this.moveToState("InGameState", {
|
||||
savegame,
|
||||
seed: Number(seedInput.getValue()),
|
||||
allowNonPrimaryColors: allowColorsCheckbox.getValue(),
|
||||
fullShapePercentage: Number(fullShapePercentageInput.getValue()),
|
||||
wierdShapePercentage: Number(wierdShapePercentageInput.getValue()),
|
||||
});
|
||||
this.app.analytics.trackUiClick("startgame_adcomplete");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onWegameRatingClicked() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user