mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Introduce game modes and get rid of global level definitions etc
This commit is contained in:
@@ -1,202 +1,203 @@
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { T } from "../../../translations";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { blueprintShape } from "../../upgrades";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
|
||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(blueprintShape);
|
||||
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
||||
|
||||
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
||||
|
||||
makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost);
|
||||
const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], "");
|
||||
this.costDisplayText = makeDiv(costContainer, null, ["costText"], "");
|
||||
costContainer.appendChild(blueprintCostShapeCanvas);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
|
||||
|
||||
/** @type {TypedTrackedState<Blueprint?>} */
|
||||
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
|
||||
/** @type {Blueprint?} */
|
||||
this.lastBlueprintUsed = null;
|
||||
|
||||
const keyActionMapper = this.root.keyMapper;
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
|
||||
|
||||
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
|
||||
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
|
||||
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
|
||||
}
|
||||
|
||||
abortPlacement() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.currentBlueprint.set(null);
|
||||
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the layer was changed
|
||||
* @param {Layer} layer
|
||||
*/
|
||||
onEditModeChanged(layer) {
|
||||
// Check if the layer of the blueprint differs and thus we have to deselect it
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (blueprint) {
|
||||
if (blueprint.layer !== layer) {
|
||||
this.currentBlueprint.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint is now affordable or not
|
||||
* @param {boolean} canAfford
|
||||
*/
|
||||
onCanAffordChanged(canAfford) {
|
||||
this.costDisplayParent.classList.toggle("canAfford", canAfford);
|
||||
}
|
||||
|
||||
update() {
|
||||
const currentBlueprint = this.currentBlueprint.get();
|
||||
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
|
||||
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint was changed
|
||||
* @param {Blueprint} blueprint
|
||||
*/
|
||||
onBlueprintChanged(blueprint) {
|
||||
if (blueprint) {
|
||||
this.lastBlueprintUsed = blueprint;
|
||||
this.costDisplayText.innerText = "" + blueprint.getCost();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mouse down pre handler
|
||||
* @param {Vector} pos
|
||||
* @param {enumMouseButton} button
|
||||
*/
|
||||
onMouseDown(pos, button) {
|
||||
if (button === enumMouseButton.right) {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.abortPlacement();
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blueprint.canAfford(this.root)) {
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(pos);
|
||||
const tile = worldPos.toTileSpace();
|
||||
if (blueprint.tryPlace(this.root, tile)) {
|
||||
const cost = blueprint.getCost();
|
||||
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
|
||||
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mose move handler
|
||||
*/
|
||||
onMouseMove() {
|
||||
// Prevent movement while blueprint is selected
|
||||
if (this.currentBlueprint.get()) {
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an array of bulidings was selected
|
||||
* @param {Array<number>} uids
|
||||
*/
|
||||
createBlueprintFromBuildings(uids) {
|
||||
if (uids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to rotate the current blueprint
|
||||
*/
|
||||
rotateBlueprint() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
|
||||
this.currentBlueprint.get().rotateCcw();
|
||||
} else {
|
||||
this.currentBlueprint.get().rotateCw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to paste the last blueprint
|
||||
*/
|
||||
pasteBlueprint() {
|
||||
if (this.lastBlueprintUsed !== null) {
|
||||
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
|
||||
// Not compatible
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.hud.signals.pasteBlueprintRequested.dispatch();
|
||||
this.currentBlueprint.set(this.lastBlueprintUsed);
|
||||
} else {
|
||||
this.root.soundProxy.playUiError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(parameters) {
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
const mousePosition = this.root.app.mousePosition;
|
||||
if (!mousePosition) {
|
||||
// Not on screen
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||
const tile = worldPos.toTileSpace();
|
||||
blueprint.draw(parameters, tile);
|
||||
}
|
||||
}
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { T } from "../../../translations";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(
|
||||
this.root.gameMode.getBlueprintShapeKey()
|
||||
);
|
||||
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
||||
|
||||
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
||||
|
||||
makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost);
|
||||
const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], "");
|
||||
this.costDisplayText = makeDiv(costContainer, null, ["costText"], "");
|
||||
costContainer.appendChild(blueprintCostShapeCanvas);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
|
||||
|
||||
/** @type {TypedTrackedState<Blueprint?>} */
|
||||
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
|
||||
/** @type {Blueprint?} */
|
||||
this.lastBlueprintUsed = null;
|
||||
|
||||
const keyActionMapper = this.root.keyMapper;
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
|
||||
|
||||
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
|
||||
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
|
||||
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
|
||||
}
|
||||
|
||||
abortPlacement() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.currentBlueprint.set(null);
|
||||
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the layer was changed
|
||||
* @param {Layer} layer
|
||||
*/
|
||||
onEditModeChanged(layer) {
|
||||
// Check if the layer of the blueprint differs and thus we have to deselect it
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (blueprint) {
|
||||
if (blueprint.layer !== layer) {
|
||||
this.currentBlueprint.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint is now affordable or not
|
||||
* @param {boolean} canAfford
|
||||
*/
|
||||
onCanAffordChanged(canAfford) {
|
||||
this.costDisplayParent.classList.toggle("canAfford", canAfford);
|
||||
}
|
||||
|
||||
update() {
|
||||
const currentBlueprint = this.currentBlueprint.get();
|
||||
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
|
||||
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint was changed
|
||||
* @param {Blueprint} blueprint
|
||||
*/
|
||||
onBlueprintChanged(blueprint) {
|
||||
if (blueprint) {
|
||||
this.lastBlueprintUsed = blueprint;
|
||||
this.costDisplayText.innerText = "" + blueprint.getCost();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mouse down pre handler
|
||||
* @param {Vector} pos
|
||||
* @param {enumMouseButton} button
|
||||
*/
|
||||
onMouseDown(pos, button) {
|
||||
if (button === enumMouseButton.right) {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.abortPlacement();
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blueprint.canAfford(this.root)) {
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(pos);
|
||||
const tile = worldPos.toTileSpace();
|
||||
if (blueprint.tryPlace(this.root, tile)) {
|
||||
const cost = blueprint.getCost();
|
||||
this.root.hubGoals.takeShapeByKey(this.root.gameMode.getBlueprintShapeKey(), cost);
|
||||
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mose move handler
|
||||
*/
|
||||
onMouseMove() {
|
||||
// Prevent movement while blueprint is selected
|
||||
if (this.currentBlueprint.get()) {
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an array of bulidings was selected
|
||||
* @param {Array<number>} uids
|
||||
*/
|
||||
createBlueprintFromBuildings(uids) {
|
||||
if (uids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to rotate the current blueprint
|
||||
*/
|
||||
rotateBlueprint() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
|
||||
this.currentBlueprint.get().rotateCcw();
|
||||
} else {
|
||||
this.currentBlueprint.get().rotateCw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to paste the last blueprint
|
||||
*/
|
||||
pasteBlueprint() {
|
||||
if (this.lastBlueprintUsed !== null) {
|
||||
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
|
||||
// Not compatible
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.hud.signals.pasteBlueprintRequested.dispatch();
|
||||
this.currentBlueprint.set(this.lastBlueprintUsed);
|
||||
} else {
|
||||
this.root.soundProxy.playUiError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(parameters) {
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
const mousePosition = this.root.app.mousePosition;
|
||||
if (!mousePosition) {
|
||||
// Not on screen
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||
const tile = worldPos.toTileSpace();
|
||||
blueprint.draw(parameters, tile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
import { tutorialGoals } from "../../tutorial_goals";
|
||||
|
||||
export class HUDSandboxController extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
@@ -75,10 +73,11 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
}
|
||||
|
||||
giveBlueprints() {
|
||||
if (!this.root.hubGoals.storedShapes[blueprintShape]) {
|
||||
this.root.hubGoals.storedShapes[blueprintShape] = 0;
|
||||
const shape = this.root.gameMode.getBlueprintShapeKey();
|
||||
if (!this.root.hubGoals.storedShapes[shape]) {
|
||||
this.root.hubGoals.storedShapes[shape] = 0;
|
||||
}
|
||||
this.root.hubGoals.storedShapes[blueprintShape] += 1e9;
|
||||
this.root.hubGoals.storedShapes[shape] += 1e9;
|
||||
}
|
||||
|
||||
maxOutAll() {
|
||||
@@ -89,7 +88,7 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
}
|
||||
|
||||
modifyUpgrade(id, amount) {
|
||||
const upgradeTiers = UPGRADES[id];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[id];
|
||||
const maxLevel = upgradeTiers.length;
|
||||
|
||||
this.root.hubGoals.upgradeLevels[id] = Math.max(
|
||||
@@ -122,9 +121,10 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
|
||||
// Compute gained rewards
|
||||
hubGoals.gainedRewards = {};
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
for (let i = 0; i < hubGoals.level - 1; ++i) {
|
||||
if (i < tutorialGoals.length) {
|
||||
const reward = tutorialGoals[i].reward;
|
||||
if (i < levels.length) {
|
||||
const reward = levels[i].reward;
|
||||
hubGoals.gainedRewards[reward] = (hubGoals.gainedRewards[reward] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { UPGRADES } from "../../upgrades";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
@@ -21,7 +20,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
this.upgradeToElements = {};
|
||||
|
||||
// Upgrades
|
||||
for (const upgradeId in UPGRADES) {
|
||||
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||
const handle = {};
|
||||
handle.requireIndexToElement = [];
|
||||
|
||||
@@ -59,7 +58,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
rerenderFull() {
|
||||
for (const upgradeId in this.upgradeToElements) {
|
||||
const handle = this.upgradeToElements[upgradeId];
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
|
||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||
const currentTierMultiplier = this.root.hubGoals.upgradeImprovements[upgradeId];
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { T } from "../../../translations";
|
||||
import { defaultBuildingVariant } from "../../meta_building";
|
||||
import { enumHubGoalRewards, tutorialGoals } from "../../tutorial_goals";
|
||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
|
||||
export class HUDUnlockNotification extends BaseHUDPart {
|
||||
@@ -53,7 +53,9 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
showForLevel(level, reward) {
|
||||
this.root.soundProxy.playUi(SOUNDS.levelComplete);
|
||||
|
||||
if (level > tutorialGoals.length) {
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
// Don't use getIsFreeplay() because we want the freeplay level up to show
|
||||
if (level > levels.length) {
|
||||
this.root.hud.signals.notification.dispatch(
|
||||
T.ingame.notifications.freeplayLevelComplete.replace("<level>", String(level)),
|
||||
enumNotificationType.success
|
||||
|
||||
Reference in New Issue
Block a user