1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2026-03-02 03:39:21 +00:00

Initial support for saving games

This commit is contained in:
tobspr
2020-05-14 21:54:11 +02:00
parent 23874c43dc
commit b01d38e55d
44 changed files with 690 additions and 777 deletions

View File

@@ -2,21 +2,21 @@ import {
Math_abs,
Math_ceil,
Math_floor,
Math_max,
Math_min,
Math_random,
performanceNow,
Math_max,
} from "../core/builtins";
import { Rectangle } from "../core/rectangle";
import { Signal, STOP_PROPAGATION } from "../core/signal";
import { clamp, lerp } from "../core/utils";
import { mixVector, Vector } from "../core/vector";
import { globalConfig } from "../core/config";
import { GameRoot } from "./root";
import { BasicSerializableObject, types } from "../savegame/serialization";
import { clickDetectorGlobals } from "../core/click_detector";
import { globalConfig } from "../core/config";
import { createLogger } from "../core/logging";
import { queryParamOptions } from "../core/query_parameters";
import { Rectangle } from "../core/rectangle";
import { Signal, STOP_PROPAGATION } from "../core/signal";
import { clamp } from "../core/utils";
import { mixVector, Vector } from "../core/vector";
import { BasicSerializableObject, types } from "../savegame/serialization";
import { GameRoot } from "./root";
const logger = createLogger("camera");

View File

@@ -1,11 +1,18 @@
import { Component } from "../component";
import { ShapeDefinition } from "../shape_definition";
import { types } from "../../savegame/serialization";
export class HubComponent extends Component {
static getId() {
return "Hub";
}
static getSchema() {
return {
definitionsToAnalyze: types.array(types.knownType(ShapeDefinition)),
};
}
constructor() {
super();

View File

@@ -3,6 +3,7 @@ import { Vector, enumDirection, enumDirectionToAngle, enumInvertedDirections } f
import { BaseItem } from "../base_item";
import { ShapeItem } from "../items/shape_item";
import { ColorItem } from "../items/color_item";
import { types } from "../../savegame/serialization";
/**
* @enum {string?}
@@ -26,7 +27,13 @@ export class ItemAcceptorComponent extends Component {
static getSchema() {
return {
// slots: "TODO",
slots: types.array(
types.structured({
pos: types.vector,
directions: types.array(types.enum(enumDirection)),
filter: types.nullable(types.enum(enumItemAcceptorItemFilter)),
})
),
};
}
@@ -35,7 +42,7 @@ export class ItemAcceptorComponent extends Component {
* @param {object} param0
* @param {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemAcceptorItemFilter}>} param0.slots The slots from which we accept items
*/
constructor({ slots }) {
constructor({ slots = [] }) {
super();
this.setSlots(slots);

View File

@@ -1,7 +1,8 @@
import { globalConfig } from "../../core/config";
import { Vector, enumDirection, enumDirectionToVector } from "../../core/vector";
import { BaseItem } from "../base_item";
import { Component } from "../component";
import { types } from "../../savegame/serialization";
import { gItemRegistry } from "../../core/global_registries";
/**
* @typedef {{
@@ -19,7 +20,15 @@ export class ItemEjectorComponent extends Component {
static getSchema() {
return {
// slots: "TODO"
instantEject: types.bool,
slots: types.array(
types.structured({
pos: types.vector,
direction: types.enum(enumDirection),
item: types.nullable(types.obj(gItemRegistry)),
progress: types.ufloat,
})
),
};
}
@@ -29,7 +38,7 @@ export class ItemEjectorComponent extends Component {
* @param {Array<{pos: Vector, direction: enumDirection}>} param0.slots The slots to eject on
* @param {boolean=} param0.instantEject If the ejection is instant
*/
constructor({ slots, instantEject = false }) {
constructor({ slots = [], instantEject = false }) {
super();
// How long items take to eject

View File

@@ -1,6 +1,8 @@
import { BaseItem } from "../base_item";
import { Component } from "../component";
import { enumDirection, Vector } from "../../core/vector";
import { types } from "../../savegame/serialization";
import { gItemRegistry } from "../../core/global_registries";
/** @enum {string} */
export const enumItemProcessorTypes = {
@@ -21,7 +23,37 @@ export class ItemProcessorComponent extends Component {
static getSchema() {
return {
// TODO
nextOutputSlot: types.uint,
type: types.enum(enumItemProcessorTypes),
inputsPerCharge: types.uint,
beltUnderlays: types.array(
types.structured({
pos: types.vector,
direction: types.enum(enumDirection),
})
),
inputSlots: types.array(
types.structured({
item: types.obj(gItemRegistry),
sourceSlot: types.uint,
})
),
itemsToEject: types.array(
types.structured({
item: types.obj(gItemRegistry),
requiredSlot: types.nullable(types.uint),
preferredSlot: types.nullable(types.uint),
})
),
secondsUntilEject: types.ufloat,
itemConsumptionAnimations: types.array(
types.structured({
item: types.obj(gItemRegistry),
slotIndex: types.uint,
animProgress: types.ufloat,
direction: types.enum(enumDirection),
})
),
};
}

View File

@@ -14,9 +14,8 @@ export class MinerComponent extends Component {
}
/**
* @param {object} param0
*/
constructor({}) {
constructor() {
super();
this.lastMiningTime = 0;
}

View File

@@ -13,7 +13,14 @@ export class StaticMapEntityComponent extends Component {
}
static getSchema() {
return {};
return {
origin: types.tileVector,
tileSize: types.tileVector,
rotation: types.float,
originalRotation: types.float,
spriteKey: types.nullable(types.string),
silhouetteColor: types.nullable(types.string),
};
}
/**

View File

@@ -1,6 +1,8 @@
import { BaseItem } from "../base_item";
import { Component } from "../component";
import { globalConfig } from "../../core/config";
import { types } from "../../savegame/serialization";
import { gItemRegistry } from "../../core/global_registries";
/** @enum {string} */
export const enumUndergroundBeltMode = {
@@ -13,6 +15,13 @@ export class UndergroundBeltComponent extends Component {
return "UndergroundBelt";
}
static getSchema() {
return {
mode: types.enum(enumUndergroundBeltMode),
pendingItems: types.array(types.pair(types.obj(gItemRegistry), types.number)),
};
}
/**
*
* @param {object} param0

View File

@@ -11,7 +11,6 @@ import { getDeviceDPI, resizeHighDPICanvas } from "../core/dpi_manager";
import { DrawParameters } from "../core/draw_parameters";
import { gMetaBuildingRegistry } from "../core/global_registries";
import { createLogger } from "../core/logging";
import { PerlinNoise } from "../core/perlin_noise";
import { Vector } from "../core/vector";
import { Savegame } from "../savegame/savegame";
import { SavegameSerializer } from "../savegame/savegame_serializer";
@@ -31,6 +30,7 @@ import { ShapeDefinitionManager } from "./shape_definition_manager";
import { SoundProxy } from "./sound_proxy";
import { GameTime } from "./time/game_time";
import { ProductionAnalytics } from "./production_analytics";
import { randomInt } from "../core/utils";
const logger = createLogger("ingame/core");
@@ -112,7 +112,6 @@ export class GameCore {
root.shapeDefinitionMgr = new ShapeDefinitionManager(root);
root.hubGoals = new HubGoals(root);
root.productionAnalytics = new ProductionAnalytics(root);
root.mapNoiseGenerator = new PerlinNoise(Math.random()); // TODO: Save seed
root.buffers = new BufferMaintainer(root);
// Initialize the hud once everything is loaded
@@ -136,6 +135,7 @@ export class GameCore {
initNewGame() {
logger.log("Initializing new game");
this.root.gameIsFresh = true;
this.root.map.seed = randomInt(0, 100000);
gMetaBuildingRegistry.findByClass(MetaHubBuilding).createAndPlaceEntity({
root: this.root,

View File

@@ -5,14 +5,13 @@ import { Component } from "./component";
/* typehints:end */
import { globalConfig } from "../core/config";
import { Vector, enumDirectionToVector, enumDirectionToAngle } from "../core/vector";
import { enumDirectionToVector, enumDirectionToAngle } from "../core/vector";
import { BasicSerializableObject, types } from "../savegame/serialization";
import { EntityComponentStorage } from "./entity_components";
import { Loader } from "../core/loader";
import { drawRotatedSprite } from "../core/draw_utils";
import { Math_radians } from "../core/builtins";
// import { gFactionRegistry, gComponentRegistry } from "../core/global_registries";
// import { EntityComponentStorage } from "./entity_components";
import { gComponentRegistry } from "../core/global_registries";
export class Entity extends BasicSerializableObject {
/**
@@ -78,7 +77,7 @@ export class Entity extends BasicSerializableObject {
static getSchema() {
return {
uid: types.uint,
// components: types.keyValueMap(types.objData(gComponentRegistry), false)
components: types.keyValueMap(types.objData(gComponentRegistry), false),
};
}

View File

@@ -0,0 +1,8 @@
import { RegularGameSpeed } from "./time/regular_game_speed";
import { gGameSpeedRegistry } from "../core/global_registries";
export function initGameSpeedRegistry() {
gGameSpeedRegistry.register(RegularGameSpeed);
// Others are disabled for now
}

View File

@@ -1,23 +1,43 @@
import { BasicSerializableObject } from "../savegame/serialization";
import { GameRoot } from "./root";
import { ShapeDefinition, enumSubShape } from "./shape_definition";
import { enumColors, enumShortcodeToColor, enumColorToShortcode } from "./colors";
import { randomChoice, clamp, randomInt, findNiceIntegerValue } from "../core/utils";
import { tutorialGoals, enumHubGoalRewards } from "./tutorial_goals";
import { createLogger } from "../core/logging";
import { globalConfig } from "../core/config";
import { Math_random } from "../core/builtins";
import { UPGRADES } from "./upgrades";
import { enumItemProcessorTypes } from "./components/item_processor";
import { globalConfig } from "../core/config";
import { queryParamOptions } from "../core/query_parameters";
const logger = createLogger("hub_goals");
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
import { BasicSerializableObject, types } from "../savegame/serialization";
import { enumColors } from "./colors";
import { enumItemProcessorTypes } from "./components/item_processor";
import { GameRoot } from "./root";
import { enumSubShape, ShapeDefinition } from "./shape_definition";
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
import { UPGRADES } from "./upgrades";
export class HubGoals extends BasicSerializableObject {
static getId() {
return "HubGoals";
}
static getSchema() {
return {
level: types.uint,
storedShapes: types.keyValueMap(types.uint),
upgradeLevels: types.keyValueMap(types.uint),
currentGoal: types.structured({
definition: types.knownType(ShapeDefinition),
required: types.uint,
reward: types.nullable(types.enum(enumHubGoalRewards)),
}),
};
}
deserialize(data) {
const errorCode = super.deserialize(data);
if (errorCode) {
return errorCode;
}
console.error("TODO: HubGoals deserialize() properly");
}
/**
* @param {GameRoot} root
*/
@@ -30,6 +50,7 @@ export class HubGoals extends BasicSerializableObject {
/**
* Which story rewards we already gained
* @type {Object.<string, number>}
*/
this.gainedRewards = {};

View File

@@ -1,20 +1,18 @@
import { BaseHUDPart } from "../base_hud_part";
import { makeDiv } from "../../../core/utils";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { MetaBuilding } from "../../meta_building";
import { MetaSplitterBuilding } from "../../buildings/splitter";
import { MetaCutterBuilding } from "../../buildings/cutter";
import { enumHubGoalRewards } from "../../tutorial_goals";
import { MetaTrashBuilding } from "../../buildings/trash";
import { MetaMinerBuilding } from "../../buildings/miner";
import { MetaPainterBuilding } from "../../buildings/painter";
import { MetaMixerBuilding } from "../../buildings/mixer";
import { MetaRotaterBuilding } from "../../buildings/rotater";
import { MetaStackerBuilding } from "../../buildings/stacker";
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { globalConfig } from "../../../core/config";
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { makeDiv } from "../../../core/utils";
import { SOUNDS } from "../../../platform/sound";
import { MetaCutterBuilding } from "../../buildings/cutter";
import { MetaMixerBuilding } from "../../buildings/mixer";
import { MetaPainterBuilding } from "../../buildings/painter";
import { MetaRotaterBuilding } from "../../buildings/rotater";
import { MetaSplitterBuilding } from "../../buildings/splitter";
import { MetaStackerBuilding } from "../../buildings/stacker";
import { MetaTrashBuilding } from "../../buildings/trash";
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { enumHubGoalRewards, enumHubGoalRewardToString } from "../../tutorial_goals";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
export class HUDUnlockNotification extends BaseHUDPart {
initialize() {
@@ -58,10 +56,14 @@ export class HUDUnlockNotification extends BaseHUDPart {
this.trackClicks(this.btnClose, this.close);
}
/**
* @param {number} level
* @param {enumHubGoalRewards} reward
*/
showForLevel(level, reward) {
this.elemTitle.innerText = "Level " + ("" + level).padStart(2, "0");
let html = `<span class='reward'>Unlocked ${reward}!</span>`;
let html = `<span class='reward'>Unlocked ${enumHubGoalRewardToString[reward]}!</span>`;
const addBuildingExplanation = metaBuildingClass => {
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);

View File

@@ -1,13 +1,9 @@
import { DrawParameters } from "../../core/draw_parameters";
import { createLogger } from "../../core/logging";
import { extendSchema } from "../../savegame/serialization";
import { BaseItem } from "../base_item";
import { enumColorsToHexCode, enumColors } from "../colors";
import { makeOffscreenBuffer } from "../../core/buffer_utils";
import { globalConfig } from "../../core/config";
import { round1Digit } from "../../core/utils";
import { Math_max, Math_round } from "../../core/builtins";
import { smoothenDpi } from "../../core/dpi_manager";
import { DrawParameters } from "../../core/draw_parameters";
import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item";
import { enumColors, enumColorsToHexCode } from "../colors";
/** @enum {string} */
const enumColorToMapBackground = {
@@ -22,9 +18,15 @@ export class ColorItem extends BaseItem {
}
static getSchema() {
return extendSchema(BaseItem.getCachedSchema(), {
// TODO
});
return types.enum(enumColors);
}
serialize() {
return this.color;
}
deserialize(data) {
this.color = data;
}
/**
@@ -33,7 +35,6 @@ export class ColorItem extends BaseItem {
constructor(color) {
super();
this.color = color;
this.bufferGenerator = this.internalGenerateColorBuffer.bind(this);
}

View File

@@ -1,10 +1,7 @@
import { BaseItem } from "../base_item";
import { DrawParameters } from "../../core/draw_parameters";
import { extendSchema } from "../../savegame/serialization";
import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item";
import { ShapeDefinition } from "../shape_definition";
import { createLogger } from "../../core/logging";
const logger = createLogger("shape_item");
export class ShapeItem extends BaseItem {
static getId() {
@@ -12,9 +9,15 @@ export class ShapeItem extends BaseItem {
}
static getSchema() {
return extendSchema(BaseItem.getCachedSchema(), {
// TODO
});
return types.string;
}
serialize() {
return this.definition.getHash();
}
deserialize(data) {
this.definition = ShapeDefinition.fromShortKey(data);
}
/**

View File

@@ -9,17 +9,32 @@ import { Math_floor } from "../core/builtins";
import { createLogger } from "../core/logging";
import { BaseItem } from "./base_item";
import { MapChunkView } from "./map_chunk_view";
import { randomInt } from "../core/utils";
import { BasicSerializableObject, types } from "../savegame/serialization";
const logger = createLogger("map");
export class BaseMap {
export class BaseMap extends BasicSerializableObject {
static getId() {
return "Map";
}
static getSchema() {
return {
seed: types.uint,
};
}
/**
*
* @param {GameRoot} root
*/
constructor(root) {
super();
this.root = root;
this.seed = 0;
/**
* Mapping of 'X|Y' to chunk
* @type {Map<string, MapChunkView>} */

View File

@@ -2,16 +2,10 @@
import { GameRoot } from "./root";
/* typehints:end */
import { Math_ceil, Math_max, Math_min, Math_random, Math_round } from "../core/builtins";
import { Math_ceil, Math_max, Math_min, Math_round } from "../core/builtins";
import { globalConfig } from "../core/config";
import { createLogger } from "../core/logging";
import {
clamp,
fastArrayDeleteValueIfContained,
make2DUndefinedArray,
randomChoice,
randomInt,
} from "../core/utils";
import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils";
import { Vector } from "../core/vector";
import { BaseItem } from "./base_item";
import { enumColors } from "./colors";
@@ -19,6 +13,7 @@ import { Entity } from "./entity";
import { ColorItem } from "./items/color_item";
import { ShapeItem } from "./items/shape_item";
import { enumSubShape } from "./shape_definition";
import { RandomNumberGenerator } from "../core/rng";
const logger = createLogger("map_chunk");
@@ -64,17 +59,18 @@ export class MapChunk {
/**
* Generates a patch filled with the given item
* @param {RandomNumberGenerator} rng
* @param {number} patchSize
* @param {BaseItem} item
* @param {number=} overrideX Override the X position of the patch
* @param {number=} overrideY Override the Y position of the patch
*/
internalGeneratePatch(patchSize, item, overrideX = null, overrideY = null) {
internalGeneratePatch(rng, patchSize, item, overrideX = null, overrideY = null) {
const border = Math_ceil(patchSize / 2 + 3);
// Find a position within the chunk which is not blocked
let patchX = randomInt(border, globalConfig.mapChunkSize - border - 1);
let patchY = randomInt(border, globalConfig.mapChunkSize - border - 1);
let patchX = rng.nextIntRange(border, globalConfig.mapChunkSize - border - 1);
let patchY = rng.nextIntRange(border, globalConfig.mapChunkSize - border - 1);
if (overrideX !== null) {
patchX = overrideX;
@@ -89,7 +85,6 @@ export class MapChunk {
// Each patch consists of multiple circles
const numCircles = patchSize;
// const numCircles = 1;
for (let i = 0; i <= numCircles; ++i) {
// Determine circle parameters
@@ -98,11 +93,11 @@ export class MapChunk {
const circleOffsetRadius = (numCircles - i) / 2 + 2;
// We draw an elipsis actually
const circleScaleY = 1 + (Math_random() * 2 - 1) * 0.1;
const circleScaleX = 1 + (Math_random() * 2 - 1) * 0.1;
const circleScaleX = rng.nextRange(0.9, 1.1);
const circleScaleY = rng.nextRange(0.9, 1.1);
const circleX = patchX + randomInt(-circleOffsetRadius, circleOffsetRadius);
const circleY = patchY + randomInt(-circleOffsetRadius, circleOffsetRadius);
const circleX = patchX + rng.nextIntRange(-circleOffsetRadius, circleOffsetRadius);
const circleY = patchY + rng.nextIntRange(-circleOffsetRadius, circleOffsetRadius);
for (let dx = -circleRadius * circleScaleX - 2; dx <= circleRadius * circleScaleX + 2; ++dx) {
for (let dy = -circleRadius * circleScaleY - 2; dy <= circleRadius * circleScaleY + 2; ++dy) {
@@ -135,24 +130,26 @@ export class MapChunk {
/**
* Generates a color patch
* @param {RandomNumberGenerator} rng
* @param {number} colorPatchSize
* @param {number} distanceToOriginInChunks
*/
internalGenerateColorPatch(colorPatchSize, distanceToOriginInChunks) {
internalGenerateColorPatch(rng, colorPatchSize, distanceToOriginInChunks) {
// First, determine available colors
let availableColors = [enumColors.red, enumColors.green];
if (distanceToOriginInChunks > 2) {
availableColors.push(enumColors.blue);
}
this.internalGeneratePatch(colorPatchSize, new ColorItem(randomChoice(availableColors)));
this.internalGeneratePatch(rng, colorPatchSize, new ColorItem(rng.choice(availableColors)));
}
/**
* Generates a shape patch
* @param {RandomNumberGenerator} rng
* @param {number} shapePatchSize
* @param {number} distanceToOriginInChunks
*/
internalGenerateShapePatch(shapePatchSize, distanceToOriginInChunks) {
internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks) {
/** @type {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} */
let subShapes = null;
@@ -174,37 +171,38 @@ export class MapChunk {
if (distanceToOriginInChunks < 7) {
// Initial chunk patches always have the same shape
const subShape = this.internalGenerateRandomSubShape(weights);
const subShape = this.internalGenerateRandomSubShape(rng, weights);
subShapes = [subShape, subShape, subShape, subShape];
} else if (distanceToOriginInChunks < 17) {
// Later patches can also have mixed ones
const subShapeA = this.internalGenerateRandomSubShape(weights);
const subShapeB = this.internalGenerateRandomSubShape(weights);
const subShapeA = this.internalGenerateRandomSubShape(rng, weights);
const subShapeB = this.internalGenerateRandomSubShape(rng, weights);
subShapes = [subShapeA, subShapeA, subShapeB, subShapeB];
} else {
// Finally there is a mix of everything
subShapes = [
this.internalGenerateRandomSubShape(weights),
this.internalGenerateRandomSubShape(weights),
this.internalGenerateRandomSubShape(weights),
this.internalGenerateRandomSubShape(weights),
this.internalGenerateRandomSubShape(rng, weights),
this.internalGenerateRandomSubShape(rng, weights),
this.internalGenerateRandomSubShape(rng, weights),
this.internalGenerateRandomSubShape(rng, weights),
];
}
const definition = this.root.shapeDefinitionMgr.getDefinitionFromSimpleShapes(subShapes);
this.internalGeneratePatch(shapePatchSize, new ShapeItem(definition));
this.internalGeneratePatch(rng, shapePatchSize, new ShapeItem(definition));
}
/**
* Chooses a random shape with the given weights
* @param {RandomNumberGenerator} rng
* @param {Object.<enumSubShape, number>} weights
* @returns {enumSubShape}
*/
internalGenerateRandomSubShape(weights) {
internalGenerateRandomSubShape(rng, weights) {
// @ts-ignore
const sum = Object.values(weights).reduce((a, b) => a + b, 0);
const chosenNumber = randomInt(0, sum - 1);
const chosenNumber = rng.nextIntRange(0, sum - 1);
let accumulated = 0;
for (const key in weights) {
const weight = weights[key];
@@ -222,7 +220,9 @@ export class MapChunk {
* Generates the lower layer "terrain"
*/
generateLowerLayer() {
if (this.generatePredefined()) {
const rng = new RandomNumberGenerator(this.x + "|" + this.y + "|" + this.root.map.seed);
if (this.generatePredefined(rng)) {
return;
}
@@ -231,27 +231,28 @@ export class MapChunk {
// Determine how likely it is that there is a color patch
const colorPatchChance = 0.9 - clamp(distanceToOriginInChunks / 25, 0, 1) * 0.5;
if (Math_random() < colorPatchChance) {
if (rng.next() < colorPatchChance) {
const colorPatchSize = Math_max(2, Math_round(1 + clamp(distanceToOriginInChunks / 8, 0, 4)));
this.internalGenerateColorPatch(colorPatchSize, distanceToOriginInChunks);
this.internalGenerateColorPatch(rng, colorPatchSize, distanceToOriginInChunks);
}
// Determine how likely it is that there is a shape patch
const shapePatchChance = 0.9 - clamp(distanceToOriginInChunks / 25, 0, 1) * 0.5;
if (Math_random() < shapePatchChance) {
if (rng.next() < shapePatchChance) {
const shapePatchSize = Math_max(2, Math_round(1 + clamp(distanceToOriginInChunks / 8, 0, 4)));
this.internalGenerateShapePatch(shapePatchSize, distanceToOriginInChunks);
this.internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks);
}
}
/**
* Checks if this chunk has predefined contents, and if so returns true and generates the
* predefined contents
* @param {RandomNumberGenerator} rng
* @returns {boolean}
*/
generatePredefined() {
generatePredefined(rng) {
if (this.x === 0 && this.y === 0) {
this.internalGeneratePatch(2, new ColorItem(enumColors.red), 7, 7);
this.internalGeneratePatch(rng, 2, new ColorItem(enumColors.red), 7, 7);
return true;
}
if (this.x === -1 && this.y === 0) {
@@ -261,7 +262,7 @@ export class MapChunk {
enumSubShape.circle,
enumSubShape.circle,
]);
this.internalGeneratePatch(2, new ShapeItem(definition), globalConfig.mapChunkSize - 9, 7);
this.internalGeneratePatch(rng, 2, new ShapeItem(definition), globalConfig.mapChunkSize - 9, 7);
return true;
}
if (this.x === 0 && this.y === -1) {
@@ -271,12 +272,12 @@ export class MapChunk {
enumSubShape.rect,
enumSubShape.rect,
]);
this.internalGeneratePatch(2, new ShapeItem(definition), 5, globalConfig.mapChunkSize - 7);
this.internalGeneratePatch(rng, 2, new ShapeItem(definition), 5, globalConfig.mapChunkSize - 7);
return true;
}
if (this.x === -1 && this.y === -1) {
this.internalGeneratePatch(2, new ColorItem(enumColors.green));
this.internalGeneratePatch(rng, 2, new ColorItem(enumColors.green));
return true;
}

View File

@@ -2,7 +2,6 @@
import { Signal } from "../core/signal";
import { RandomNumberGenerator } from "../core/rng";
// import { gFactionRegistry } from "./global_registries";
import { createLogger } from "../core/logging";
// Type hints
@@ -11,12 +10,9 @@ import { GameTime } from "./time/game_time";
import { EntityManager } from "./entity_manager";
import { GameSystemManager } from "./game_system_manager";
import { GameHUD } from "./hud/hud";
// import { GameLogic } from "./game_logic";
import { MapView } from "./map_view";
import { Camera } from "./camera";
// import { ParticleManager } from "../particles/particle_manager";
import { InGameState } from "../states/ingame";
// import { CanvasClickInterceptor } from "/canvas_click_interceptor";
import { AutomaticSave } from "./automatic_save";
import { Application } from "../application";
import { SoundProxy } from "./sound_proxy";
@@ -99,21 +95,12 @@ export class GameRoot {
/** @type {GameTime} */
this.time = null;
/** @type {PerlinNoise} */
this.mapNoiseGenerator = null;
/** @type {HubGoals} */
this.hubGoals = null;
/** @type {BufferMaintainer} */
this.buffers = null;
// /** @type {ParticleManager} */
// this.particleMgr = null;
// /** @type {ParticleManager} */
// this.uiParticleMgr = null;
/** @type {CanvasClickInterceptor} */
this.canvasClickInterceptor = null;
@@ -123,9 +110,6 @@ export class GameRoot {
/** @type {SoundProxy} */
this.soundProxy = null;
// /** @type {MinimapRenderer} */
// this.minimapRenderer = null;
/** @type {ShapeDefinitionManager} */
this.shapeDefinitionMgr = null;
@@ -147,7 +131,6 @@ export class GameRoot {
// Game Hooks
gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved
gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored
gameOver: /** @type {TypedSignal<[]>} */ (new Signal()), // Game over
storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()),
upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()),
@@ -182,20 +165,6 @@ export class GameRoot {
this.reset();
}
/**
* Prepares the root for game over, this sets the right flags and
* detaches all signals so no bad stuff happens
*/
prepareGameOver() {
this.gameInitialized = false;
this.logicInitialized = false;
// for (const key in this.signals) {
// if (key !== "aboutToDestruct") {
// this.signals[key].removeAll();
// }
// }
}
/**
* Resets the whole root and removes all properties
*/

View File

@@ -5,7 +5,7 @@ import { smoothenDpi } from "../core/dpi_manager";
import { DrawParameters } from "../core/draw_parameters";
import { createLogger } from "../core/logging";
import { Vector } from "../core/vector";
import { BasicSerializableObject } from "../savegame/serialization";
import { BasicSerializableObject, types } from "../savegame/serialization";
import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors";
const rusha = require("rusha");
@@ -74,6 +74,23 @@ export class ShapeDefinition extends BasicSerializableObject {
return "ShapeDefinition";
}
static getSchema() {
return {};
}
deserialize(data) {
const errorCode = super.deserialize(data);
if (errorCode) {
return errorCode;
}
const definition = ShapeDefinition.fromShortKey(data);
this.layers = definition.layers;
}
serialize() {
return this.getHash();
}
/**
*
* @param {object} param0

View File

@@ -3,6 +3,7 @@ import { HubComponent } from "../components/hub";
import { DrawParameters } from "../../core/draw_parameters";
import { Entity } from "../entity";
import { formatBigNumber } from "../../core/utils";
import { enumHubGoalRewardToString } from "../tutorial_goals";
export class HubSystem extends GameSystemWithFilter {
constructor(root) {
@@ -77,7 +78,7 @@ export class HubSystem extends GameSystemWithFilter {
context.font = "bold 11px GameFont";
context.fillStyle = "#fd0752";
context.textAlign = "center";
context.fillText(goals.reward.toUpperCase(), pos.x, pos.y + 46);
context.fillText(enumHubGoalRewardToString[goals.reward].toUpperCase(), pos.x, pos.y + 46);
// Level
context.font = "bold 11px GameFont";

View File

@@ -4,15 +4,30 @@ import { ShapeDefinition } from "./shape_definition";
* @enum {string}
*/
export const enumHubGoalRewards = {
reward_cutter_and_trash: "Cutting Shapes",
reward_rotater: "Rotating",
reward_painter: "Painting",
reward_mixer: "Color Mixing",
reward_stacker: "Combiner",
reward_splitter: "Splitter/Merger",
reward_tunnel: "Tunnel",
reward_cutter_and_trash: "reward_cutter_and_trash",
reward_rotater: "reward_rotater",
reward_painter: "reward_painter",
reward_mixer: "reward_mixer",
reward_stacker: "reward_stacker",
reward_splitter: "reward_splitter",
reward_tunnel: "reward_tunnel",
no_reward: "Next level",
no_reward: "no_reward",
};
/**
* @enum {string}
*/
export const enumHubGoalRewardToString = {
[enumHubGoalRewards.reward_cutter_and_trash]: "Cutting Shapes",
[enumHubGoalRewards.reward_rotater]: "Rotating",
[enumHubGoalRewards.reward_painter]: "Painting",
[enumHubGoalRewards.reward_mixer]: "Color Mixing",
[enumHubGoalRewards.reward_stacker]: "Combiner",
[enumHubGoalRewards.reward_splitter]: "Splitter/Merger",
[enumHubGoalRewards.reward_tunnel]: "Tunnel",
[enumHubGoalRewards.no_reward]: "Next level",
};
export const tutorialGoals = [