mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Merge branch 'master' of https://github.com/tobspr/shapez.io into modloader
This commit is contained in:
commit
42ba0d1340
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -42,6 +42,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd gulp
|
cd gulp
|
||||||
yarn gulp translations.fullBuild
|
yarn gulp translations.fullBuild
|
||||||
|
yarn gulp localConfig.findOrCreate
|
||||||
cd ..
|
cd ..
|
||||||
yarn tslint
|
yarn tslint
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export class AchievementProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.darkMode);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.darkMode, null);
|
||||||
|
|
||||||
if (this.has(ACHIEVEMENTS.mam)) {
|
if (this.has(ACHIEVEMENTS.mam)) {
|
||||||
this.root.signals.entityAdded.add(this.onMamFailure, this);
|
this.root.signals.entityAdded.add(this.onMamFailure, this);
|
||||||
@ -136,7 +136,7 @@ export class AchievementProxy {
|
|||||||
this.root.signals.entityDestroyed.add(this.onMamFailure, this);
|
this.root.signals.entityDestroyed.add(this.onMamFailure, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.mam);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.mam, null);
|
||||||
|
|
||||||
// reset on every level
|
// reset on every level
|
||||||
this.root.savegame.currentData.stats.failedMam = false;
|
this.root.savegame.currentData.stats.failedMam = false;
|
||||||
|
@ -110,6 +110,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
|
|||||||
// KEYBINDINGS
|
// KEYBINDINGS
|
||||||
const keyActionMapper = this.root.keyMapper;
|
const keyActionMapper = this.root.keyMapper;
|
||||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.tryRotate, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.tryRotate, this);
|
||||||
|
|
||||||
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateToUp).add(this.trySetRotate, this);
|
||||||
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateToDown).add(this.trySetRotate, this);
|
||||||
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateToRight).add(this.trySetRotate, this);
|
||||||
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateToLeft).add(this.trySetRotate, this);
|
||||||
|
|
||||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildingVariants).add(this.cycleVariants, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildingVariants).add(this.cycleVariants, this);
|
||||||
keyActionMapper
|
keyActionMapper
|
||||||
.getBinding(KEYMAPPINGS.placement.switchDirectionLockSide)
|
.getBinding(KEYMAPPINGS.placement.switchDirectionLockSide)
|
||||||
@ -290,6 +296,28 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
|
|||||||
staticComp.rotation = this.currentBaseRotation;
|
staticComp.rotation = this.currentBaseRotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotates the current building to the specified direction.
|
||||||
|
*/
|
||||||
|
trySetRotate() {
|
||||||
|
const selectedBuilding = this.currentMetaBuilding.get();
|
||||||
|
if (selectedBuilding) {
|
||||||
|
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateToUp).pressed) {
|
||||||
|
this.currentBaseRotation = 0;
|
||||||
|
} else if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateToDown).pressed) {
|
||||||
|
this.currentBaseRotation = 180;
|
||||||
|
} else if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateToRight).pressed) {
|
||||||
|
this.currentBaseRotation = 90;
|
||||||
|
} else if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateToLeft).pressed) {
|
||||||
|
this.currentBaseRotation = 270;
|
||||||
|
}
|
||||||
|
|
||||||
|
const staticComp = this.fakeEntity.components.StaticMapEntity;
|
||||||
|
staticComp.rotation = this.currentBaseRotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to delete the building under the mouse
|
* Tries to delete the building under the mouse
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +12,11 @@ function key(str) {
|
|||||||
return str.toUpperCase().charCodeAt(0);
|
return str.toUpperCase().charCodeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const KEYCODE_UP_ARROW = 38;
|
||||||
|
const KEYCODE_DOWN_ARROW = 40;
|
||||||
|
const KEYCODE_LEFT_ARROW = 37;
|
||||||
|
const KEYCODE_RIGHT_ARROW = 39;
|
||||||
|
|
||||||
export const KEYMAPPINGS = {
|
export const KEYMAPPINGS = {
|
||||||
general: {
|
general: {
|
||||||
confirm: { keyCode: 13 }, // enter
|
confirm: { keyCode: 13 }, // enter
|
||||||
@ -82,6 +87,10 @@ export const KEYMAPPINGS = {
|
|||||||
pipette: { keyCode: key("Q") },
|
pipette: { keyCode: key("Q") },
|
||||||
rotateWhilePlacing: { keyCode: key("R") },
|
rotateWhilePlacing: { keyCode: key("R") },
|
||||||
rotateInverseModifier: { keyCode: 16 }, // SHIFT
|
rotateInverseModifier: { keyCode: 16 }, // SHIFT
|
||||||
|
rotateToUp: { keyCode: KEYCODE_UP_ARROW },
|
||||||
|
rotateToDown: { keyCode: KEYCODE_DOWN_ARROW },
|
||||||
|
rotateToRight: { keyCode: KEYCODE_RIGHT_ARROW },
|
||||||
|
rotateToLeft: { keyCode: KEYCODE_LEFT_ARROW },
|
||||||
cycleBuildingVariants: { keyCode: key("T") },
|
cycleBuildingVariants: { keyCode: key("T") },
|
||||||
cycleBuildings: { keyCode: 9 }, // TAB
|
cycleBuildings: { keyCode: 9 }, // TAB
|
||||||
switchDirectionLockSide: { keyCode: key("R") },
|
switchDirectionLockSide: { keyCode: key("R") },
|
||||||
@ -163,13 +172,13 @@ export function getStringForKeyCode(code) {
|
|||||||
return "END";
|
return "END";
|
||||||
case 36:
|
case 36:
|
||||||
return "HOME";
|
return "HOME";
|
||||||
case 37:
|
case KEYCODE_LEFT_ARROW:
|
||||||
return "⬅";
|
return "⬅";
|
||||||
case 38:
|
case KEYCODE_UP_ARROW:
|
||||||
return "⬆";
|
return "⬆";
|
||||||
case 39:
|
case KEYCODE_RIGHT_ARROW:
|
||||||
return "➡";
|
return "➡";
|
||||||
case 40:
|
case KEYCODE_DOWN_ARROW:
|
||||||
return "⬇";
|
return "⬇";
|
||||||
case 44:
|
case 44:
|
||||||
return "PRNT";
|
return "PRNT";
|
||||||
|
@ -181,7 +181,7 @@ export class GameRoot {
|
|||||||
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
|
|
||||||
// Called with an achievement key and necessary args to validate it can be unlocked.
|
// Called with an achievement key and necessary args to validate it can be unlocked.
|
||||||
achievementCheck: /** @type {TypedSignal<(string|any)[]>} */ (new Signal()),
|
achievementCheck: /** @type {TypedSignal<[string, any]>} */ (new Signal()),
|
||||||
bulkAchievementCheck: /** @type {TypedSignal<(string|any)[]>} */ (new Signal()),
|
bulkAchievementCheck: /** @type {TypedSignal<(string|any)[]>} */ (new Signal()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
||||||
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
||||||
|
|
||||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.cutShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.cutShape, null);
|
||||||
|
|
||||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
|
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
|
||||||
this.registerOrReturnHandle(rightSide),
|
this.registerOrReturnHandle(rightSide),
|
||||||
@ -140,7 +140,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
|
|
||||||
const rotated = definition.cloneRotateCW();
|
const rotated = definition.cloneRotateCW();
|
||||||
|
|
||||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.rotateShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.rotateShape, null);
|
||||||
|
|
||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||||
rotated
|
rotated
|
||||||
@ -195,7 +195,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.stackShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.stackShape, null);
|
||||||
|
|
||||||
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||||
@ -215,7 +215,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.paintShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.paintShape, null);
|
||||||
|
|
||||||
const colorized = definition.cloneAndPaintWith(color);
|
const colorized = definition.cloneAndPaintWith(color);
|
||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
import { Application } from "../application";
|
import { Application } from "../application";
|
||||||
import { Entity } from "../game/entity";
|
import { Entity } from "../game/entity";
|
||||||
import { GameRoot } from "../game/root";
|
import { GameRoot } from "../game/root";
|
||||||
import { ShapeDefinition } from "../game/shape_definition";
|
|
||||||
import { VANILLA_THEMES } from "../game/theme";
|
import { VANILLA_THEMES } from "../game/theme";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { enumAnalyticsDataSource } from "../game/production_analytics";
|
import { enumAnalyticsDataSource } from "../game/production_analytics";
|
||||||
|
import { ShapeDefinition } from "../game/shape_definition";
|
||||||
import { ShapeItem } from "../game/items/shape_item";
|
import { ShapeItem } from "../game/items/shape_item";
|
||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { codes } from "../modloader/old_buildings_codes";
|
import { codes } from "../modloader/old_buildings_codes";
|
||||||
@ -172,14 +172,8 @@ export class AchievementCollection {
|
|||||||
isValid: this.isBelt500TilesValid,
|
isValid: this.isBelt500TilesValid,
|
||||||
signal: "entityAdded",
|
signal: "entityAdded",
|
||||||
});
|
});
|
||||||
this.add(ACHIEVEMENTS.blueprint100k, {
|
this.add(ACHIEVEMENTS.blueprint100k, this.createBlueprintOptions(100000));
|
||||||
isValid: this.isBlueprint100kValid,
|
this.add(ACHIEVEMENTS.blueprint1m, this.createBlueprintOptions(1000000));
|
||||||
signal: "shapeDelivered",
|
|
||||||
});
|
|
||||||
this.add(ACHIEVEMENTS.blueprint1m, {
|
|
||||||
isValid: this.isBlueprint1mValid,
|
|
||||||
signal: "shapeDelivered",
|
|
||||||
});
|
|
||||||
this.add(ACHIEVEMENTS.completeLvl26, this.createLevelOptions(26));
|
this.add(ACHIEVEMENTS.completeLvl26, this.createLevelOptions(26));
|
||||||
this.add(ACHIEVEMENTS.cutShape);
|
this.add(ACHIEVEMENTS.cutShape);
|
||||||
this.add(ACHIEVEMENTS.darkMode, {
|
this.add(ACHIEVEMENTS.darkMode, {
|
||||||
@ -244,10 +238,12 @@ export class AchievementCollection {
|
|||||||
});
|
});
|
||||||
this.add(ACHIEVEMENTS.stackShape);
|
this.add(ACHIEVEMENTS.stackShape);
|
||||||
this.add(ACHIEVEMENTS.store100Unique, {
|
this.add(ACHIEVEMENTS.store100Unique, {
|
||||||
|
init: this.initStore100Unique,
|
||||||
isValid: this.isStore100UniqueValid,
|
isValid: this.isStore100UniqueValid,
|
||||||
signal: "shapeDelivered",
|
signal: "shapeDelivered",
|
||||||
});
|
});
|
||||||
this.add(ACHIEVEMENTS.storeShape, {
|
this.add(ACHIEVEMENTS.storeShape, {
|
||||||
|
init: this.initStoreShape,
|
||||||
isValid: this.isStoreShapeValid,
|
isValid: this.isStoreShapeValid,
|
||||||
});
|
});
|
||||||
this.add(ACHIEVEMENTS.throughputBp25, this.createRateOptions(SHAPE_BP, 25));
|
this.add(ACHIEVEMENTS.throughputBp25, this.createRateOptions(SHAPE_BP, 25));
|
||||||
@ -272,14 +268,14 @@ export class AchievementCollection {
|
|||||||
this.root.signals.bulkAchievementCheck.add(this.bulkUnlock, this);
|
this.root.signals.bulkAchievementCheck.add(this.bulkUnlock, this);
|
||||||
|
|
||||||
for (let [key, achievement] of this.map.entries()) {
|
for (let [key, achievement] of this.map.entries()) {
|
||||||
if (achievement.init) {
|
|
||||||
achievement.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (achievement.signal) {
|
if (achievement.signal) {
|
||||||
achievement.receiver = this.unlock.bind(this, key);
|
achievement.receiver = this.unlock.bind(this, key);
|
||||||
this.root.signals[achievement.signal].add(achievement.receiver);
|
this.root.signals[achievement.signal].add(achievement.receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (achievement.init) {
|
||||||
|
achievement.init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.hasDefaultReceivers()) {
|
if (!this.hasDefaultReceivers()) {
|
||||||
@ -327,7 +323,7 @@ export class AchievementCollection {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key - Maps to an Achievement
|
* @param {string} key - Maps to an Achievement
|
||||||
* @param {?*} data - Data received from signal dispatches for validation
|
* @param {any} data - Data received from signal dispatches for validation
|
||||||
*/
|
*/
|
||||||
unlock(key, data) {
|
unlock(key, data) {
|
||||||
if (!this.map.has(key)) {
|
if (!this.map.has(key)) {
|
||||||
@ -420,8 +416,18 @@ export class AchievementCollection {
|
|||||||
return item.getItemType() === ITEM_SHAPE && item.definition.getHash() === shape;
|
return item.getItemType() === ITEM_SHAPE && item.definition.getHash() === shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createBlueprintOptions(count) {
|
||||||
|
return {
|
||||||
|
init: ({ key }) => this.unlock(key, ShapeDefinition.fromShortKey(SHAPE_BP)),
|
||||||
|
isValid: definition =>
|
||||||
|
definition.cachedHash === SHAPE_BP && this.root.hubGoals.storedShapes[SHAPE_BP] >= count,
|
||||||
|
signal: "shapeDelivered",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
createLevelOptions(level) {
|
createLevelOptions(level) {
|
||||||
return {
|
return {
|
||||||
|
init: ({ key }) => this.unlock(key, this.root.hubGoals.level),
|
||||||
isValid: currentLevel => currentLevel >= level,
|
isValid: currentLevel => currentLevel >= level,
|
||||||
signal: "storyGoalCompleted",
|
signal: "storyGoalCompleted",
|
||||||
};
|
};
|
||||||
@ -464,6 +470,7 @@ export class AchievementCollection {
|
|||||||
|
|
||||||
createUpgradeOptions(tier) {
|
createUpgradeOptions(tier) {
|
||||||
return {
|
return {
|
||||||
|
init: ({ key }) => this.unlock(key, null),
|
||||||
isValid: () => this.hasAllUpgradesAtLeastAtTier(tier),
|
isValid: () => this.hasAllUpgradesAtLeastAtTier(tier),
|
||||||
signal: "upgradePurchased",
|
signal: "upgradePurchased",
|
||||||
};
|
};
|
||||||
@ -474,16 +481,6 @@ export class AchievementCollection {
|
|||||||
return entity.components.Belt && entity.components.Belt.assignedPath.totalLength >= 500;
|
return entity.components.Belt && entity.components.Belt.assignedPath.totalLength >= 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
|
||||||
isBlueprint100kValid(definition) {
|
|
||||||
return definition.cachedHash === SHAPE_BP && this.root.hubGoals.storedShapes[SHAPE_BP] >= 100000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
|
||||||
isBlueprint1mValid(definition) {
|
|
||||||
return definition.cachedHash === SHAPE_BP && this.root.hubGoals.storedShapes[SHAPE_BP] >= 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
isDarkModeValid() {
|
isDarkModeValid() {
|
||||||
return this.root.app.settings.currentData.settings.theme === DARK_MODE;
|
return this.root.app.settings.currentData.settings.theme === DARK_MODE;
|
||||||
@ -524,7 +521,7 @@ export class AchievementCollection {
|
|||||||
return this.root.hubGoals.level < 18 && this.isShape(item, SHAPE_LOGO);
|
return this.root.hubGoals.level < 18 && this.isShape(item, SHAPE_LOGO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @params {number} level @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
isMamValid() {
|
isMamValid() {
|
||||||
return this.root.hubGoals.level > 27 && !this.root.savegame.currentData.stats.failedMam;
|
return this.root.hubGoals.level > 27 && !this.root.savegame.currentData.stats.failedMam;
|
||||||
}
|
}
|
||||||
@ -596,11 +593,21 @@ export class AchievementCollection {
|
|||||||
return item.getItemType() === ITEM_SHAPE && item.definition.layers.length === 4;
|
return item.getItemType() === ITEM_SHAPE && item.definition.layers.length === 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {Achievement} achievement */
|
||||||
|
initStore100Unique({ key }) {
|
||||||
|
this.unlock(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
/** @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
isStore100UniqueValid() {
|
isStore100UniqueValid() {
|
||||||
return Object.keys(this.root.hubGoals.storedShapes).length >= 100;
|
return Object.keys(this.root.hubGoals.storedShapes).length >= 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {Achievement} achievement */
|
||||||
|
initStoreShape({ key }) {
|
||||||
|
this.unlock(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
/** @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
isStoreShapeValid() {
|
isStoreShapeValid() {
|
||||||
const entities = this.root.systemMgr.systems.storage.allEntities;
|
const entities = this.root.systemMgr.systems.storage.allEntities;
|
||||||
@ -618,15 +625,17 @@ export class AchievementCollection {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
initTrash1000() {
|
/** @param {Achievement} achievement */
|
||||||
|
initTrash1000({ key }) {
|
||||||
if (Number(this.root.savegame.currentData.stats.trashedCount)) {
|
if (Number(this.root.savegame.currentData.stats.trashedCount)) {
|
||||||
|
this.unlock(key, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.savegame.currentData.stats.trashedCount = 0;
|
this.root.savegame.currentData.stats.trashedCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @params {number} count @returns {boolean} */
|
/** @param {number} count @returns {boolean} */
|
||||||
isTrash1000Valid(count) {
|
isTrash1000Valid(count) {
|
||||||
this.root.savegame.currentData.stats.trashedCount += count;
|
this.root.savegame.currentData.stats.trashedCount += count;
|
||||||
|
|
||||||
|
@ -1138,6 +1138,10 @@ keybindings:
|
|||||||
rotateWhilePlacing: Rotate
|
rotateWhilePlacing: Rotate
|
||||||
rotateInverseModifier: >-
|
rotateInverseModifier: >-
|
||||||
Modifier: Rotate CCW instead
|
Modifier: Rotate CCW instead
|
||||||
|
rotateToUp: "Rotate: Point Up"
|
||||||
|
rotateToDown: "Rotate: Point Down"
|
||||||
|
rotateToRight: "Rotate: Point Right"
|
||||||
|
rotateToLeft: "Rotate: Point Left"
|
||||||
cycleBuildingVariants: Cycle Variants
|
cycleBuildingVariants: Cycle Variants
|
||||||
confirmMassDelete: Delete area
|
confirmMassDelete: Delete area
|
||||||
pasteLastBlueprint: Paste last blueprint
|
pasteLastBlueprint: Paste last blueprint
|
||||||
|
Loading…
Reference in New Issue
Block a user