mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Load css resources async, improve building descriptions
This commit is contained in:
@@ -50,7 +50,6 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba($mainBgColor, 0.9) uiResource("loading.svg") center center / #{D(60px)} no-repeat;
|
||||
@include InlineAnimation(0.2s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
@@ -59,6 +58,11 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: rgba($mainBgColor, 0.9) uiResource("loading.svg") center center / #{D(60px)} no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,11 +391,15 @@ canvas {
|
||||
color: #393747;
|
||||
&::after {
|
||||
content: " ";
|
||||
background: uiResource("loading.svg") center center / contain no-repeat;
|
||||
@include S(width, 35px);
|
||||
@include S(height, 35px);
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("loading.svg") center center / contain no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
@include InlineAnimation(1.5s ease-in-out infinite) {
|
||||
@@ -451,7 +455,6 @@ canvas {
|
||||
.prefab_InfoIcon {
|
||||
@include S(width, 25px);
|
||||
@include S(height, 25px);
|
||||
// background: uiResource("icons_small/info.png") center center / contain no-repeat;
|
||||
z-index: 100;
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
@@ -468,7 +471,6 @@ canvas {
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
.loadingImage {
|
||||
background: uiResource("loading.svg") center center / #{D(40px)} no-repeat;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
@@ -478,6 +480,11 @@ canvas {
|
||||
transform: scale(1.2) rotate(160deg);
|
||||
}
|
||||
}
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("loading.svg") center center / #{D(40px)} no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
.prefab_GameHint {
|
||||
|
||||
@@ -69,14 +69,18 @@
|
||||
|
||||
&::before {
|
||||
content: " ";
|
||||
background: uiResource("locked_building.png") center center / #{D(20px)} #{D(20px)}
|
||||
no-repeat;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 4;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("locked_building.png") center center / #{D(20px)} #{D(20px)}
|
||||
no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,13 +122,16 @@
|
||||
opacity: 0.7;
|
||||
@include S(width, 20px);
|
||||
@include S(height, 20px);
|
||||
background: uiResource("icons/close.png") center center / 80% no-repeat;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
&:hover {
|
||||
opacity: 0.4;
|
||||
}
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/close.png") center center / 80% no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,17 +38,26 @@
|
||||
@include DarkThemeInvert;
|
||||
|
||||
&.shop {
|
||||
background-image: uiResource("icons/shop.png");
|
||||
grid-column: 1;
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/shop.png");
|
||||
}
|
||||
}
|
||||
|
||||
&.stats {
|
||||
background-image: uiResource("icons/statistics.png");
|
||||
grid-column: 2;
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/statistics.png");
|
||||
}
|
||||
}
|
||||
|
||||
&.save {
|
||||
background-image: uiResource("icons/save.png");
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/save.png");
|
||||
}
|
||||
grid-column: 3;
|
||||
@include MakeAnimationWrappedEvenOdd(0.5s ease-in-out) {
|
||||
0% {
|
||||
@@ -83,8 +92,11 @@
|
||||
}
|
||||
|
||||
&.settings {
|
||||
background-image: uiResource("icons/settings_menu_settings.png");
|
||||
grid-column: 4;
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/settings_menu_settings.png");
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -99,9 +111,14 @@
|
||||
&.hasBadge {
|
||||
&.shop {
|
||||
filter: none;
|
||||
background-image: uiResource("icons/shop_active.png");
|
||||
opacity: 0.9;
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/shop_active.png");
|
||||
}
|
||||
}
|
||||
|
||||
transform-origin: 50% 50%;
|
||||
@include InlineAnimation(0.8s ease-in-out infinite) {
|
||||
50% {
|
||||
|
||||
@@ -47,10 +47,12 @@
|
||||
left: unset;
|
||||
margin: 0;
|
||||
&.rightMouse {
|
||||
/* @load-async */
|
||||
background: #fff uiResource("icons/mouse_right.png") center center / 85% no-repeat;
|
||||
}
|
||||
|
||||
&.leftMouse {
|
||||
/* @load-async */
|
||||
background: #fff uiResource("icons/mouse_left.png") center center / 85% no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
> .infoButton {
|
||||
@include S(width, 8px);
|
||||
@include S(height, 8px);
|
||||
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
|
||||
position: absolute;
|
||||
opacity: 0.7;
|
||||
@include S(top, 13px);
|
||||
@@ -90,6 +89,11 @@
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
&.goal,
|
||||
@@ -107,11 +111,13 @@
|
||||
|
||||
&.goal .amountLabel {
|
||||
&::after {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/current_goal_marker.png");
|
||||
background-size: 90%;
|
||||
}
|
||||
@include DarkThemeOverride {
|
||||
&::after {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/current_goal_marker_inverted.png") !important;
|
||||
}
|
||||
}
|
||||
@@ -119,11 +125,13 @@
|
||||
|
||||
&.blueprint .amountLabel {
|
||||
&::after {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/blueprint_marker.png");
|
||||
background-size: 90%;
|
||||
}
|
||||
@include DarkThemeOverride {
|
||||
&::after {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/blueprint_marker_inverted.png") !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,23 +39,29 @@
|
||||
background: transparent;
|
||||
filter: invert(1);
|
||||
|
||||
background: uiResource("icons/settings_menu_play.png") center top / contain no-repeat;
|
||||
content: "";
|
||||
opacity: 0.8;
|
||||
@include S(width, 35px);
|
||||
@include S(height, 35px);
|
||||
|
||||
&.settings {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/settings_menu_settings.png");
|
||||
}
|
||||
|
||||
&.menu {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/settings_menu_exit.png");
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/settings_menu_play.png") center top / contain no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +113,13 @@
|
||||
overflow: hidden;
|
||||
|
||||
button.pin {
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/pin.png") center center / 95% no-repeat;
|
||||
}
|
||||
|
||||
@include S(width, 12px);
|
||||
@include S(height, 12px);
|
||||
background: uiResource("icons/pin.png") center center / 95% no-repeat;
|
||||
position: absolute;
|
||||
@include S(top, 2px);
|
||||
@include S(right, 2px);
|
||||
@@ -143,6 +147,7 @@
|
||||
}
|
||||
|
||||
&.isGoal {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/current_goal_marker.png") center center / 95%
|
||||
no-repeat;
|
||||
opacity: $disabledOpacity !important;
|
||||
@@ -198,7 +203,6 @@
|
||||
button.showInfo {
|
||||
@include S(width, 11px);
|
||||
@include S(height, 11px);
|
||||
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
|
||||
position: absolute;
|
||||
@include S(top, 17px);
|
||||
@include S(right, 2.5px);
|
||||
@@ -213,6 +217,10 @@
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
button.showInfo {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
|
||||
}
|
||||
|
||||
canvas {
|
||||
@include S(width, 40px);
|
||||
|
||||
@@ -39,10 +39,12 @@
|
||||
}
|
||||
|
||||
&.displayDetailed {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/display_list.png");
|
||||
}
|
||||
|
||||
&.displayIcons {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/display_icons.png");
|
||||
background-size: #{D(11.5px)};
|
||||
}
|
||||
@@ -53,7 +55,10 @@
|
||||
}
|
||||
|
||||
&.displaySorted {
|
||||
background-image: uiResource("icons/display_sorted.png");
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/display_sorted.png");
|
||||
}
|
||||
background-size: #{D(11.5px)};
|
||||
margin-right: 5px;
|
||||
@include S(border-top-right-radius, $globalBorderRadius);
|
||||
@@ -63,7 +68,10 @@
|
||||
}
|
||||
|
||||
&.displayIterateUnit {
|
||||
background-image: uiResource("icons/toggle_unit.png");
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/toggle_unit.png");
|
||||
}
|
||||
opacity: 0.8;
|
||||
@include S(padding, 1px, 0);
|
||||
}
|
||||
|
||||
@@ -1,117 +1,120 @@
|
||||
#ingame_HUD_TutorialHints {
|
||||
position: absolute;
|
||||
@include S(left, 10px);
|
||||
@include S(bottom, 10px);
|
||||
|
||||
@include StyleBelowWidth(1430px) {
|
||||
@include S(bottom, 50px);
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgba(50, 60, 70, 0);
|
||||
|
||||
transition: all 0.2s ease-in-out;
|
||||
pointer-events: all;
|
||||
|
||||
transition-property: background-color, transform, bottom, left;
|
||||
|
||||
@include S(padding, 5px);
|
||||
video {
|
||||
transition: all 0.2s ease-in-out;
|
||||
transition-property: opacity, width;
|
||||
@include S(width, 0px);
|
||||
opacity: 0;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: #333438;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
@include S(grid-gap, 2px);
|
||||
grid-template-columns: 1fr;
|
||||
@include S(margin-bottom, 3px);
|
||||
z-index: 11;
|
||||
position: relative;
|
||||
|
||||
> span {
|
||||
@include DarkThemeInvert;
|
||||
|
||||
display: flex;
|
||||
@include SuperSmallText;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
&::before {
|
||||
@include S(margin-right, 4px);
|
||||
content: " ";
|
||||
@include S(width, 12px);
|
||||
@include S(height, 12px);
|
||||
display: inline-block;
|
||||
background: uiResource("icons/help.png") center center / 95% no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
button.toggleHint {
|
||||
@include PlainText;
|
||||
@include IncreasedClickArea(0px);
|
||||
}
|
||||
}
|
||||
|
||||
button.toggleHint {
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.enlarged {
|
||||
background: $ingameHudBg;
|
||||
left: 50%;
|
||||
bottom: 50%;
|
||||
transform: translate(-50%, 50%);
|
||||
|
||||
&::before {
|
||||
pointer-events: all;
|
||||
content: " ";
|
||||
position: fixed;
|
||||
top: -1000px;
|
||||
left: -1000px;
|
||||
right: -1000px;
|
||||
bottom: -1000px;
|
||||
z-index: 0;
|
||||
|
||||
background: rgba($ingameHudBg, 0.3);
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-template-columns: 1fr auto;
|
||||
> span {
|
||||
display: none;
|
||||
}
|
||||
button.toggleHint {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
}
|
||||
|
||||
video {
|
||||
@include InlineAnimation(0.2s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
@include S(width, 0px);
|
||||
}
|
||||
}
|
||||
|
||||
opacity: 1;
|
||||
@include S(width, 500px);
|
||||
}
|
||||
button.toggleHint {
|
||||
.hide {
|
||||
display: block;
|
||||
}
|
||||
.show {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ingame_HUD_TutorialHints {
|
||||
position: absolute;
|
||||
@include S(left, 10px);
|
||||
@include S(bottom, 10px);
|
||||
|
||||
@include StyleBelowWidth(1430px) {
|
||||
@include S(bottom, 50px);
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgba(50, 60, 70, 0);
|
||||
|
||||
transition: all 0.2s ease-in-out;
|
||||
pointer-events: all;
|
||||
|
||||
transition-property: background-color, transform, bottom, left;
|
||||
|
||||
@include S(padding, 5px);
|
||||
video {
|
||||
transition: all 0.2s ease-in-out;
|
||||
transition-property: opacity, width;
|
||||
@include S(width, 0px);
|
||||
opacity: 0;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: #333438;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
@include S(grid-gap, 2px);
|
||||
grid-template-columns: 1fr;
|
||||
@include S(margin-bottom, 3px);
|
||||
z-index: 11;
|
||||
position: relative;
|
||||
|
||||
> span {
|
||||
@include DarkThemeInvert;
|
||||
|
||||
display: flex;
|
||||
@include SuperSmallText;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
&::before {
|
||||
@include S(margin-right, 4px);
|
||||
content: " ";
|
||||
@include S(width, 12px);
|
||||
@include S(height, 12px);
|
||||
display: inline-block;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/help.png") center center / 95% no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.toggleHint {
|
||||
@include PlainText;
|
||||
@include IncreasedClickArea(0px);
|
||||
}
|
||||
}
|
||||
|
||||
button.toggleHint {
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.enlarged {
|
||||
background: $ingameHudBg;
|
||||
left: 50%;
|
||||
bottom: 50%;
|
||||
transform: translate(-50%, 50%);
|
||||
|
||||
&::before {
|
||||
pointer-events: all;
|
||||
content: " ";
|
||||
position: fixed;
|
||||
top: -1000px;
|
||||
left: -1000px;
|
||||
right: -1000px;
|
||||
bottom: -1000px;
|
||||
z-index: 0;
|
||||
|
||||
background: rgba($ingameHudBg, 0.3);
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-template-columns: 1fr auto;
|
||||
> span {
|
||||
display: none;
|
||||
}
|
||||
button.toggleHint {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
}
|
||||
|
||||
video {
|
||||
@include InlineAnimation(0.2s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
@include S(width, 0px);
|
||||
}
|
||||
}
|
||||
|
||||
opacity: 1;
|
||||
@include S(width, 500px);
|
||||
}
|
||||
button.toggleHint {
|
||||
.hide {
|
||||
display: block;
|
||||
}
|
||||
.show {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,177 +1,181 @@
|
||||
#ingame_HUD_UnlockNotification {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(#333538, 0.98) uiResource("dialog_bg_pattern.png") top left / #{D(10px)} repeat;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
pointer-events: all;
|
||||
|
||||
@include InlineAnimation(0.1s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog {
|
||||
// background: rgba(#222428, 0.5);
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
@include S(padding, 30px);
|
||||
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
.title,
|
||||
.subTitle {
|
||||
@include SuperHeading;
|
||||
text-transform: uppercase;
|
||||
@include S(font-size, 40px);
|
||||
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateY(-50vh);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(5vh);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-2vh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
@include PlainText;
|
||||
display: inline-block;
|
||||
@include S(margin, 5px, 0, 20px);
|
||||
color: $colorGreenBright;
|
||||
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateY(-60vh);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(6vh);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-3vh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contents {
|
||||
@include S(width, 400px);
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateX(-100vw);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(5vw);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(-2vw);
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include S(grid-gap, 10px);
|
||||
|
||||
.rewardName {
|
||||
grid-column: 1 / 3;
|
||||
display: none;
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateX(200vw);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-10vw);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(4vw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rewardDesc {
|
||||
grid-column: 1 / 3;
|
||||
@include PlainText;
|
||||
@include S(margin-bottom, 15px);
|
||||
color: #aaacaf;
|
||||
@include S(width, 400px);
|
||||
text-align: left;
|
||||
strong {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.images {
|
||||
display: flex;
|
||||
.buildingExplanation {
|
||||
@include S(width, 200px);
|
||||
@include S(height, 200px);
|
||||
display: inline-block;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
box-shadow: #{D(2px)} #{D(3px)} 0 0 rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.close {
|
||||
border: 0;
|
||||
position: relative;
|
||||
@include S(margin-top, 30px);
|
||||
|
||||
&:not(.unlocked) {
|
||||
pointer-events: none;
|
||||
opacity: 0.8;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.unlocked {
|
||||
&::after {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 10, 20, 0.8);
|
||||
|
||||
@include InlineAnimation(5s linear) {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ingame_HUD_UnlockNotification {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
pointer-events: all;
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: rgba(#333538, 0.98) uiResource("dialog_bg_pattern.png") top left / #{D(10px)} repeat;
|
||||
}
|
||||
|
||||
@include InlineAnimation(0.1s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog {
|
||||
// background: rgba(#222428, 0.5);
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
@include S(padding, 30px);
|
||||
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
.title,
|
||||
.subTitle {
|
||||
@include SuperHeading;
|
||||
text-transform: uppercase;
|
||||
@include S(font-size, 40px);
|
||||
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateY(-50vh);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(5vh);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-2vh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
@include PlainText;
|
||||
display: inline-block;
|
||||
@include S(margin, 5px, 0, 20px);
|
||||
color: $colorGreenBright;
|
||||
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateY(-60vh);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(6vh);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-3vh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contents {
|
||||
@include S(width, 400px);
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateX(-100vw);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(5vw);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(-2vw);
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include S(grid-gap, 10px);
|
||||
|
||||
.rewardName {
|
||||
grid-column: 1 / 3;
|
||||
display: none;
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateX(200vw);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-10vw);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(4vw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rewardDesc {
|
||||
grid-column: 1 / 3;
|
||||
@include PlainText;
|
||||
@include S(margin-bottom, 15px);
|
||||
color: #aaacaf;
|
||||
@include S(width, 400px);
|
||||
text-align: left;
|
||||
strong {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.images {
|
||||
display: flex;
|
||||
.buildingExplanation {
|
||||
@include S(width, 200px);
|
||||
@include S(height, 200px);
|
||||
display: inline-block;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
box-shadow: #{D(2px)} #{D(3px)} 0 0 rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.close {
|
||||
border: 0;
|
||||
position: relative;
|
||||
@include S(margin-top, 30px);
|
||||
|
||||
&:not(.unlocked) {
|
||||
pointer-events: none;
|
||||
opacity: 0.8;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.unlocked {
|
||||
&::after {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 10, 20, 0.8);
|
||||
|
||||
@include InlineAnimation(5s linear) {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: uiResource("vignette.lossless.png") center center / cover no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("vignette.lossless.png") center center / cover no-repeat;
|
||||
}
|
||||
pointer-events: none;
|
||||
|
||||
@include DarkThemeOverride {
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
#ingame_HUD_Watermark {
|
||||
position: absolute;
|
||||
background: uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
@include S(width, 110px);
|
||||
@include S(height, 40px);
|
||||
@include S(top, 10px);
|
||||
pointer-events: all;
|
||||
cursor: pointer;
|
||||
@include S(left, 160px);
|
||||
|
||||
transition: all 0.12s ease-in;
|
||||
transition-property: opacity, transform;
|
||||
transform: skewX(-0.5deg);
|
||||
&:hover {
|
||||
transform: skewX(-1deg) scale(1.02);
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
#ingame_HUD_Watermark {
|
||||
position: absolute;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
}
|
||||
|
||||
@include S(width, 110px);
|
||||
@include S(height, 40px);
|
||||
@include S(top, 10px);
|
||||
pointer-events: all;
|
||||
cursor: pointer;
|
||||
@include S(left, 160px);
|
||||
|
||||
transition: all 0.12s ease-in;
|
||||
transition-property: opacity, transform;
|
||||
transform: skewX(-0.5deg);
|
||||
&:hover {
|
||||
transform: skewX(-1deg) scale(1.02);
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,10 @@
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
background: uiResource("icons/waypoint.png") left 50% / #{D(8px)} no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/waypoint.png") left 50% / #{D(8px)} no-repeat;
|
||||
}
|
||||
opacity: 0.7;
|
||||
@include S(margin-bottom, 1px);
|
||||
font-weight: bold;
|
||||
@@ -68,7 +71,10 @@
|
||||
@include S(width, 10px);
|
||||
@include S(height, 10px);
|
||||
@include S(margin-left, 4px);
|
||||
background: uiResource("icons/edit_key.png") center center / 70% no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/edit_key.png") center center / 70% no-repeat;
|
||||
}
|
||||
pointer-events: all;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
@return inline($pth);
|
||||
}
|
||||
|
||||
@import "icons";
|
||||
@import "resources";
|
||||
@import "trigonometry";
|
||||
@import "material_colors";
|
||||
@import "dynamic_ui";
|
||||
|
||||
@@ -1,363 +1,316 @@
|
||||
// ----------------------------------------
|
||||
/* Forces an element to get rendered on its own layer, increasing
|
||||
the performance when animated. Use only transform and opacity in animations! */
|
||||
@mixin FastAnimation {
|
||||
will-change: transform, opacity, filter;
|
||||
// transform: translateZ(0);
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
// Helper which includes the translateZ webkit fix, use together with Fast animation
|
||||
// $hardwareAcc: translateZ(0);
|
||||
$hardwareAcc: null;
|
||||
|
||||
// ----------------------------------------
|
||||
/** Increased click area for this element, helpful on mobile */
|
||||
@mixin IncreasedClickArea($size) {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: #{D(-$size)};
|
||||
bottom: #{D(-$size)};
|
||||
left: #{D(-$size)};
|
||||
right: #{D(-$size)};
|
||||
// background: rgba(255, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
button,
|
||||
.increasedClickArea {
|
||||
position: relative;
|
||||
@include IncreasedClickArea(15px);
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Duplicates an animation and adds two classes .<classPrefix>Even and .<classPrefix>Odd which uses the
|
||||
animation. This can be used to replay the animation by toggling between the classes, because
|
||||
it is not possible to restart a css animation */
|
||||
@mixin MakeAnimationWrappedEvenOdd($duration, $classPrefix: "anim", $childSelector: "") {
|
||||
$animName: autogen_anim_#{unique-id()};
|
||||
|
||||
@at-root {
|
||||
@keyframes #{$animName}_even {
|
||||
@content;
|
||||
}
|
||||
|
||||
@keyframes #{$animName}_odd {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
&.#{$classPrefix}Even #{$childSelector} {
|
||||
animation: #{$animName}_even $duration;
|
||||
}
|
||||
|
||||
&.#{$classPrefix}Odd #{$childSelector} {
|
||||
animation: #{$animName}_odd $duration;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Allows to use and define an animation without specifying its name */
|
||||
@mixin InlineAnimation($duration) {
|
||||
$animName: autogen_anim_#{unique-id()};
|
||||
|
||||
@at-root {
|
||||
@keyframes #{$animName} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
animation: $animName $duration !important;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Animation prefab for a double bounce pop-in animation, useful for dialogs */
|
||||
@mixin DoubleBounceAnim($duration: 0.5s ease-in-out, $amount: 0.2, $initialOpacity: 0) {
|
||||
@include InlineAnimation($duration) {
|
||||
0% {
|
||||
opacity: $initialOpacity;
|
||||
transform: scale(0) $hardwareAcc;
|
||||
}
|
||||
|
||||
25% {
|
||||
opacity: 0.5;
|
||||
transform: scale(1 + $amount) $hardwareAcc;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1 - $amount * 0.5) $hardwareAcc;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: scale(1 + $amount * 0.25) $hardwareAcc;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1) $hardwareAcc;
|
||||
}
|
||||
}
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied in horizontal mode */
|
||||
@mixin HorizontalStyle {
|
||||
@include AppendGlobal(".h") {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied in vertical mode */
|
||||
@mixin VerticalStyle {
|
||||
@include AppendGlobal(".v") {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only while the hardware keyboard is open */
|
||||
@mixin AndroidHwKeyboardOpen {
|
||||
@include AppendGlobal(".kb") {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Automatically transforms the game state if a hardware keyboard is open */
|
||||
@mixin TransformToMatchKeyboard {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
@include AndroidHwKeyboardOpen {
|
||||
@include VerticalStyle {
|
||||
transform: translateY(#{D(-125px)}) $hardwareAcc;
|
||||
}
|
||||
@include HorizontalStyle {
|
||||
transform: translateY(#{D(-100px)}) $hardwareAcc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport is at least X pixels wide */
|
||||
@mixin StyleAtWidth($minW) {
|
||||
@media (min-width: #{$minW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport is at least X pixels height */
|
||||
@mixin StyleAtHeight($minH) {
|
||||
@media (min-height: #{$minH}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at least the given dimensions */
|
||||
@mixin StyleAtDims($minW, $minH) {
|
||||
@media (min-height: #{$minH}) and (min-width: #{$minW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at maximum the given dimensions */
|
||||
@mixin StyleBelowDims($maxW, $maxH) {
|
||||
@media (max-height: #{$maxH}) and (max-width: #{$maxW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at maximum the given height */
|
||||
@mixin StyleBelowHeight($maxH) {
|
||||
@media (max-height: #{$maxH}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at maximum the given width */
|
||||
@mixin StyleBelowWidth($maxW) {
|
||||
@media (max-width: #{$maxW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// Dynamic graphics quality styles
|
||||
|
||||
@mixin BoxShadow3D($bgColor, $size: 3px, $pressEffect: true) {
|
||||
background-color: $bgColor;
|
||||
|
||||
$borderSize: 1.5px;
|
||||
$borderColor: rgb(18, 20, 24);
|
||||
|
||||
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
|
||||
// 0 D($size) 0 D($borderSize) $borderColor;
|
||||
|
||||
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 D($borderSize) $borderColor,
|
||||
// D(-$size * 1.5) D($size * 2) 0 D($borderSize) rgba(0, 0, 0, 0.1);
|
||||
|
||||
// transition: box-shadow 0.1s ease-in-out;
|
||||
|
||||
// @if $pressEffect {
|
||||
// &.pressed {
|
||||
// transform: none !important;
|
||||
// $pSize: max(0, $size - 1.5px);
|
||||
// transition: none !important;
|
||||
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($pSize) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
|
||||
// 0 D($pSize) 0 D($borderSize) $borderColor;
|
||||
// top: D($size - $pSize);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@mixin BorderRadius($v1: 2px, $v2: "", $v3: "", $v4: "") {
|
||||
@include S(border-radius, $v1, $v2, $v3, $v4);
|
||||
}
|
||||
|
||||
@mixin BoxShadow($x, $y, $blur, $offset, $color) {
|
||||
box-shadow: D($x) D($y) D($blur) D($offset) $color;
|
||||
}
|
||||
|
||||
@mixin DropShadow($yOffset: 2px, $blur: 2px, $amount: 0.2) {
|
||||
@include BoxShadow(0, $yOffset, $blur, 0, rgba(#000, $amount));
|
||||
}
|
||||
|
||||
@mixin TextShadow($yOffset: 2px, $blur: 1px, $amount: 0.6) {
|
||||
text-shadow: 0 D($yOffset) D($blur) rgba(#000, $amount);
|
||||
}
|
||||
|
||||
@mixin Button3D($bgColor, $pressEffect: true) {
|
||||
@include BoxShadow3D($bgColor, 2px, $pressEffect);
|
||||
}
|
||||
|
||||
@mixin ButtonDisabled3D($bgColor) {
|
||||
@include BoxShadow3D($bgColor, 0.5px, false);
|
||||
}
|
||||
|
||||
@mixin BoxShadowInset($bgColor, $size: 3px) {
|
||||
background-color: $bgColor;
|
||||
|
||||
$borderSize: 1px;
|
||||
$borderColor: rgb(15, 19, 24);
|
||||
box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 rgba(#fff, 0.07);
|
||||
border-top: D($size) solid rgba(#000, 0.1);
|
||||
|
||||
//, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
|
||||
// 0 D($size + $borderSize) 0 0 $borderColor;
|
||||
}
|
||||
|
||||
@mixin TextShadow3D($color: rgb(222, 234, 238), $borderColor: #000) {
|
||||
color: $color;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Shine animation prefab, useful for buttons etc. Adds a bright shine which moves over
|
||||
the button like a reflection. Performance heavy. */
|
||||
@mixin ShineAnimation($duration, $bgColor, $w: 200px, $shineAlpha: 0.25, $lightenAmount: 7, $bgAnim: true) {
|
||||
$bgBase: darken($bgColor, 5);
|
||||
background-color: $bgBase;
|
||||
|
||||
@include HighQualityOrMore {
|
||||
position: relative;
|
||||
// overflow: hidden;
|
||||
// overflow: visible;
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: uiResource("misc/shine_bg.png") 0px center / 100% 100% no-repeat;
|
||||
|
||||
@include InlineAnimation($duration ease-in-out infinite) {
|
||||
0% {
|
||||
background-position-x: #{D(-$w)};
|
||||
}
|
||||
100% {
|
||||
background-position-x: #{D($w)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if ($bgAnim) {
|
||||
@include InlineAnimation($duration ease-in-out infinite) {
|
||||
0% {
|
||||
background-color: $bgBase;
|
||||
}
|
||||
50% {
|
||||
background-color: lighten($bgBase, $lightenAmount);
|
||||
}
|
||||
100% {
|
||||
background-color: $bgBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* String replacement */
|
||||
@function str-replace($string, $search, $replace: "") {
|
||||
$index: str-index($string, $search);
|
||||
|
||||
@if $index {
|
||||
@return str-slice($string, 1, $index - 1) + $replace +
|
||||
str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
@mixin BounceInFromSide($mul, $duration: 0.18s ease-in-out) {
|
||||
@include InlineAnimation($duration) {
|
||||
0% {
|
||||
transform: translateY(#{D(-100px * $mul)}) scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
@mixin BreakText {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-all;
|
||||
}
|
||||
|
||||
@mixin SupportsAndroidNotchQuery {
|
||||
@supports (color: constant(--notch-inset-left)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin SupportsiOsNotchQuery {
|
||||
@supports (color: env(safe-area-inset-left, 0px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin DarkThemeOverride {
|
||||
@at-root html[data-theme="dark"] &,
|
||||
&[data-theme="dark"] {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin DarkThemeInvert {
|
||||
@include DarkThemeOverride {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
// ----------------------------------------
|
||||
/* Forces an element to get rendered on its own layer, increasing
|
||||
the performance when animated. Use only transform and opacity in animations! */
|
||||
@mixin FastAnimation {
|
||||
will-change: transform, opacity, filter;
|
||||
// transform: translateZ(0);
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
// Helper which includes the translateZ webkit fix, use together with Fast animation
|
||||
// $hardwareAcc: translateZ(0);
|
||||
$hardwareAcc: null;
|
||||
|
||||
// ----------------------------------------
|
||||
/** Increased click area for this element, helpful on mobile */
|
||||
@mixin IncreasedClickArea($size) {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: #{D(-$size)};
|
||||
bottom: #{D(-$size)};
|
||||
left: #{D(-$size)};
|
||||
right: #{D(-$size)};
|
||||
// background: rgba(255, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
button,
|
||||
.increasedClickArea {
|
||||
position: relative;
|
||||
@include IncreasedClickArea(15px);
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Duplicates an animation and adds two classes .<classPrefix>Even and .<classPrefix>Odd which uses the
|
||||
animation. This can be used to replay the animation by toggling between the classes, because
|
||||
it is not possible to restart a css animation */
|
||||
@mixin MakeAnimationWrappedEvenOdd($duration, $classPrefix: "anim", $childSelector: "") {
|
||||
$animName: autogen_anim_#{unique-id()};
|
||||
|
||||
@at-root {
|
||||
@keyframes #{$animName}_even {
|
||||
@content;
|
||||
}
|
||||
|
||||
@keyframes #{$animName}_odd {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
&.#{$classPrefix}Even #{$childSelector} {
|
||||
animation: #{$animName}_even $duration;
|
||||
}
|
||||
|
||||
&.#{$classPrefix}Odd #{$childSelector} {
|
||||
animation: #{$animName}_odd $duration;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Allows to use and define an animation without specifying its name */
|
||||
@mixin InlineAnimation($duration) {
|
||||
$animName: autogen_anim_#{unique-id()};
|
||||
|
||||
@at-root {
|
||||
@keyframes #{$animName} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
animation: $animName $duration !important;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Animation prefab for a double bounce pop-in animation, useful for dialogs */
|
||||
@mixin DoubleBounceAnim($duration: 0.5s ease-in-out, $amount: 0.2, $initialOpacity: 0) {
|
||||
@include InlineAnimation($duration) {
|
||||
0% {
|
||||
opacity: $initialOpacity;
|
||||
transform: scale(0) $hardwareAcc;
|
||||
}
|
||||
|
||||
25% {
|
||||
opacity: 0.5;
|
||||
transform: scale(1 + $amount) $hardwareAcc;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1 - $amount * 0.5) $hardwareAcc;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: scale(1 + $amount * 0.25) $hardwareAcc;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1) $hardwareAcc;
|
||||
}
|
||||
}
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied in horizontal mode */
|
||||
@mixin HorizontalStyle {
|
||||
@include AppendGlobal(".h") {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied in vertical mode */
|
||||
@mixin VerticalStyle {
|
||||
@include AppendGlobal(".v") {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only while the hardware keyboard is open */
|
||||
@mixin AndroidHwKeyboardOpen {
|
||||
@include AppendGlobal(".kb") {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Automatically transforms the game state if a hardware keyboard is open */
|
||||
@mixin TransformToMatchKeyboard {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
@include AndroidHwKeyboardOpen {
|
||||
@include VerticalStyle {
|
||||
transform: translateY(#{D(-125px)}) $hardwareAcc;
|
||||
}
|
||||
@include HorizontalStyle {
|
||||
transform: translateY(#{D(-100px)}) $hardwareAcc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport is at least X pixels wide */
|
||||
@mixin StyleAtWidth($minW) {
|
||||
@media (min-width: #{$minW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport is at least X pixels height */
|
||||
@mixin StyleAtHeight($minH) {
|
||||
@media (min-height: #{$minH}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at least the given dimensions */
|
||||
@mixin StyleAtDims($minW, $minH) {
|
||||
@media (min-height: #{$minH}) and (min-width: #{$minW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at maximum the given dimensions */
|
||||
@mixin StyleBelowDims($maxW, $maxH) {
|
||||
@media (max-height: #{$maxH}) and (max-width: #{$maxW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at maximum the given height */
|
||||
@mixin StyleBelowHeight($maxH) {
|
||||
@media (max-height: #{$maxH}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
// ----------------------------------------
|
||||
/* Define a style which is only applied when the viewport has at maximum the given width */
|
||||
@mixin StyleBelowWidth($maxW) {
|
||||
@media (max-width: #{$maxW}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// Dynamic graphics quality styles
|
||||
|
||||
@mixin BoxShadow3D($bgColor, $size: 3px, $pressEffect: true) {
|
||||
background-color: $bgColor;
|
||||
|
||||
$borderSize: 1.5px;
|
||||
$borderColor: rgb(18, 20, 24);
|
||||
|
||||
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
|
||||
// 0 D($size) 0 D($borderSize) $borderColor;
|
||||
|
||||
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 D($borderSize) $borderColor,
|
||||
// D(-$size * 1.5) D($size * 2) 0 D($borderSize) rgba(0, 0, 0, 0.1);
|
||||
|
||||
// transition: box-shadow 0.1s ease-in-out;
|
||||
|
||||
// @if $pressEffect {
|
||||
// &.pressed {
|
||||
// transform: none !important;
|
||||
// $pSize: max(0, $size - 1.5px);
|
||||
// transition: none !important;
|
||||
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($pSize) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
|
||||
// 0 D($pSize) 0 D($borderSize) $borderColor;
|
||||
// top: D($size - $pSize);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@mixin BorderRadius($v1: 2px, $v2: "", $v3: "", $v4: "") {
|
||||
@include S(border-radius, $v1, $v2, $v3, $v4);
|
||||
}
|
||||
|
||||
@mixin BoxShadow($x, $y, $blur, $offset, $color) {
|
||||
box-shadow: D($x) D($y) D($blur) D($offset) $color;
|
||||
}
|
||||
|
||||
@mixin DropShadow($yOffset: 2px, $blur: 2px, $amount: 0.2) {
|
||||
@include BoxShadow(0, $yOffset, $blur, 0, rgba(#000, $amount));
|
||||
}
|
||||
|
||||
@mixin TextShadow($yOffset: 2px, $blur: 1px, $amount: 0.6) {
|
||||
text-shadow: 0 D($yOffset) D($blur) rgba(#000, $amount);
|
||||
}
|
||||
|
||||
@mixin Button3D($bgColor, $pressEffect: true) {
|
||||
@include BoxShadow3D($bgColor, 2px, $pressEffect);
|
||||
}
|
||||
|
||||
@mixin ButtonDisabled3D($bgColor) {
|
||||
@include BoxShadow3D($bgColor, 0.5px, false);
|
||||
}
|
||||
|
||||
@mixin BoxShadowInset($bgColor, $size: 3px) {
|
||||
background-color: $bgColor;
|
||||
|
||||
$borderSize: 1px;
|
||||
$borderColor: rgb(15, 19, 24);
|
||||
box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 rgba(#fff, 0.07);
|
||||
border-top: D($size) solid rgba(#000, 0.1);
|
||||
|
||||
//, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
|
||||
// 0 D($size + $borderSize) 0 0 $borderColor;
|
||||
}
|
||||
|
||||
@mixin TextShadow3D($color: rgb(222, 234, 238), $borderColor: #000) {
|
||||
color: $color;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* String replacement */
|
||||
@function str-replace($string, $search, $replace: "") {
|
||||
$index: str-index($string, $search);
|
||||
|
||||
@if $index {
|
||||
@return str-slice($string, 1, $index - 1) + $replace +
|
||||
str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
@mixin BounceInFromSide($mul, $duration: 0.18s ease-in-out) {
|
||||
@include InlineAnimation($duration) {
|
||||
0% {
|
||||
transform: translateY(#{D(-100px * $mul)}) scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
@mixin BreakText {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-all;
|
||||
}
|
||||
|
||||
@mixin SupportsAndroidNotchQuery {
|
||||
@supports (color: constant(--notch-inset-left)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin SupportsiOsNotchQuery {
|
||||
@supports (color: env(safe-area-inset-left, 0px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin DarkThemeOverride {
|
||||
@at-root html[data-theme="dark"] &,
|
||||
&[data-theme="dark"] {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin DarkThemeInvert {
|
||||
@include DarkThemeOverride {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,17 @@ $buildings: belt, cutter, miner, mixer, painter, rotater, balancer, stacker, tra
|
||||
|
||||
@each $building in $buildings {
|
||||
[data-icon="building_icons/#{$building}.png"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("res/ui/building_icons/#{$building}.png") !important;
|
||||
}
|
||||
}
|
||||
|
||||
$buildingsAndVariants: belt, balancer, balancer-merger, balancer-splitter, underground_belt,
|
||||
underground_belt-tier2, miner, miner-chainable, cutter, cutter-quad, rotater, rotater-ccw, rotater-fl,
|
||||
stacker, mixer, painter, painter-double, painter-quad, trash, storage;
|
||||
stacker, mixer, painter, painter-double, painter-quad, trash, storage, reader;
|
||||
@each $building in $buildingsAndVariants {
|
||||
[data-icon="building_tutorials/#{$building}.png"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("res/ui/building_tutorials/#{$building}.png") !important;
|
||||
}
|
||||
}
|
||||
@@ -20,18 +22,22 @@ $buildingsAndVariants: belt, balancer, balancer-merger, balancer-splitter, under
|
||||
|
||||
// Special cases for mirrored vairants
|
||||
[data-icon="building_tutorials/painter-mirrored.png"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("res/ui/building_tutorials/painter.png") !important;
|
||||
}
|
||||
[data-icon="building_tutorials/balancer-merger-inverse.png"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("res/ui/building_tutorials/balancer-merger.png") !important;
|
||||
}
|
||||
[data-icon="building_tutorials/balancer-splitter-inverse.png"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("res/ui/building_tutorials/balancer-splitter.png") !important;
|
||||
}
|
||||
|
||||
$icons: notification_saved, notification_success, notification_upgrade;
|
||||
@each $icon in $icons {
|
||||
[data-icon="icons/#{$icon}.png"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("res/ui/icons/#{$icon}.png") !important;
|
||||
}
|
||||
}
|
||||
@@ -41,6 +47,7 @@ $languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW
|
||||
|
||||
@each $language in $languages {
|
||||
[data-languageicon="#{$language}"] {
|
||||
/* @load-async */
|
||||
background-image: uiResource("languages/#{$language}.svg") !important;
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,12 @@
|
||||
background: transparent center center / 40% no-repeat;
|
||||
opacity: 0.9;
|
||||
&.editKeybinding {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/edit_key.png");
|
||||
}
|
||||
|
||||
&.resetKeybinding {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/reset_key.png");
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
@include S(height, 25px);
|
||||
pointer-events: all;
|
||||
cursor: pointer;
|
||||
background: uiResource("icons/main_menu_settings.png") center center / contain no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/main_menu_settings.png") center center / contain no-repeat;
|
||||
}
|
||||
transition: opacity 0.12s ease-in-out;
|
||||
@include IncreasedClickArea(2px);
|
||||
opacity: 0.7;
|
||||
@@ -32,6 +35,7 @@
|
||||
}
|
||||
|
||||
.exitAppButton {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/main_menu_exit.png");
|
||||
background-size: 90%;
|
||||
}
|
||||
@@ -129,8 +133,10 @@
|
||||
width: 100%;
|
||||
@include S(height, 40px);
|
||||
@include S(width, 180px);
|
||||
|
||||
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
}
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
text-indent: -999em;
|
||||
@@ -167,7 +173,10 @@
|
||||
@include S(margin, 10px, 0);
|
||||
@include S(width, 100px);
|
||||
@include S(height, 30px);
|
||||
background: uiResource("demo_badge.png") center center / contain no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("demo_badge.png") center center / contain no-repeat;
|
||||
}
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -335,14 +344,22 @@
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
@include IncreasedClickArea(0px);
|
||||
background: #44484a uiResource("icons/play.png") center center / 40% no-repeat;
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: #44484a uiResource("icons/play.png") center center / 40% no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
button.downloadGame {
|
||||
grid-column: 3 / 4;
|
||||
grid-row: 1 / 2;
|
||||
background-color: transparent;
|
||||
background-image: uiResource("icons/download.png");
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/download.png");
|
||||
}
|
||||
@include S(width, 15px);
|
||||
@include IncreasedClickArea(0px);
|
||||
@include S(height, 15px);
|
||||
@@ -362,7 +379,11 @@
|
||||
grid-row: 2 / 3;
|
||||
background-color: transparent;
|
||||
@include IncreasedClickArea(0px);
|
||||
background-image: uiResource("icons/delete.png");
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/delete.png");
|
||||
}
|
||||
@include S(width, 15px);
|
||||
@include S(height, 15px);
|
||||
align-self: end;
|
||||
@@ -379,7 +400,11 @@
|
||||
button.renameGame {
|
||||
background-color: transparent;
|
||||
@include IncreasedClickArea(2px);
|
||||
background-image: uiResource("icons/edit_key.png");
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/edit_key.png");
|
||||
}
|
||||
@include S(width, 10px);
|
||||
@include S(height, 10px);
|
||||
align-self: center;
|
||||
@@ -445,7 +470,11 @@
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
justify-content: center;
|
||||
background: $linkBg uiResource("icons/link.png") top D(3px) right D(3px) / D(9px) no-repeat;
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background: $linkBg uiResource("icons/link.png") top D(3px) right D(3px) / D(9px) no-repeat;
|
||||
}
|
||||
@include S(padding, 5px);
|
||||
@include S(padding-left, 10px);
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
@@ -472,9 +501,11 @@
|
||||
@include S(height, 50px);
|
||||
background: center center / 80% no-repeat;
|
||||
&.githubLogo {
|
||||
/* @load-async */
|
||||
background-image: uiResource("main_menu/github.png");
|
||||
}
|
||||
&.discordLogo {
|
||||
/* @load-async */
|
||||
background-image: uiResource("main_menu/discord.png");
|
||||
background-size: 95%;
|
||||
}
|
||||
@@ -516,12 +547,15 @@
|
||||
transition: background-color 0.12s ease-in-out;
|
||||
|
||||
&.redditLink {
|
||||
/* @load-async */
|
||||
background-image: uiResource("main_menu/reddit.svg");
|
||||
}
|
||||
&.changelog {
|
||||
/* @load-async */
|
||||
background-image: uiResource("main_menu/changelog.svg");
|
||||
}
|
||||
&.helpTranslate {
|
||||
/* @load-async */
|
||||
background-image: uiResource("main_menu/translate.svg");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,51 @@
|
||||
#state_MobileWarningState {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #333438 !important;
|
||||
@include S(padding, 20px);
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.logo {
|
||||
width: 80%;
|
||||
max-width: 200px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #aaacaf;
|
||||
display: block;
|
||||
margin-bottom: 13px;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
max-width: 300px;
|
||||
text-align: left;
|
||||
a {
|
||||
color: $colorBlueBright;
|
||||
}
|
||||
}
|
||||
|
||||
.standaloneLink {
|
||||
width: 200px;
|
||||
height: 80px;
|
||||
min-height: 40px;
|
||||
background: uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
text-indent: -999em;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
pointer-events: all;
|
||||
transition: all 0.12s ease-in;
|
||||
transition-property: opacity, transform;
|
||||
transform: skewX(-0.5deg);
|
||||
&:hover {
|
||||
transform: skewX(-1deg) scale(1.02);
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
#state_MobileWarningState {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #333438 !important;
|
||||
@include S(padding, 20px);
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.logo {
|
||||
width: 80%;
|
||||
max-width: 200px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #aaacaf;
|
||||
display: block;
|
||||
margin-bottom: 13px;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
max-width: 300px;
|
||||
text-align: left;
|
||||
a {
|
||||
color: $colorBlueBright;
|
||||
}
|
||||
}
|
||||
|
||||
.standaloneLink {
|
||||
width: 200px;
|
||||
height: 80px;
|
||||
min-height: 40px;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
}
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
text-indent: -999em;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
pointer-events: all;
|
||||
transition: all 0.12s ease-in;
|
||||
transition-property: opacity, transform;
|
||||
transform: skewX(-0.5deg);
|
||||
&:hover {
|
||||
transform: skewX(-1deg) scale(1.02);
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,8 +159,11 @@
|
||||
@include S(padding, 4px);
|
||||
@include S(padding-right, 15px);
|
||||
|
||||
background: #fff uiResource("icons/enum_selector.png") calc(100% - #{D(5px)})
|
||||
calc(50% + #{D(1px)}) / #{D(15px)} no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: #fff uiResource("icons/enum_selector.png") calc(100% - #{D(5px)})
|
||||
calc(50% + #{D(1px)}) / #{D(15px)} no-repeat;
|
||||
}
|
||||
|
||||
transition: background-color 0.12s ease-in-out;
|
||||
&:hover {
|
||||
@@ -196,7 +199,11 @@
|
||||
// dirty but works
|
||||
// color: #222;
|
||||
background-color: $darkModeControlsBackground;
|
||||
background-image: uiResource("icons/enum_selector_white.png");
|
||||
|
||||
& {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/enum_selector_white.png");
|
||||
}
|
||||
color: #ddd;
|
||||
&:hover {
|
||||
background-color: darken($darkModeControlsBackground, 2);
|
||||
|
||||
@@ -26,9 +26,11 @@
|
||||
@include S(height, 30px);
|
||||
@include S(margin-right, 10px);
|
||||
@include S(margin-left, -5px);
|
||||
background: uiResource("icons/state_back_button.png") center center / 70% no-repeat;
|
||||
& {
|
||||
/* @load-async */
|
||||
background: uiResource("icons/state_back_button.png") center center / 70% no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
@include S(margin-bottom, 20px);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { T } from "../../translations";
|
||||
import { formatItemsPerSecond } from "../../core/utils";
|
||||
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
|
||||
import { BeltUnderlaysComponent } from "../components/belt_underlays";
|
||||
|
||||
/** @enum {string} */
|
||||
@@ -18,6 +18,14 @@ export const enumBalancerVariants = {
|
||||
splitterInverse: "splitter-inverse",
|
||||
};
|
||||
|
||||
const overlayMatrices = {
|
||||
[defaultBuildingVariant]: null,
|
||||
[enumBalancerVariants.merger]: generateMatrixRotations([0, 1, 0, 0, 1, 1, 0, 1, 0]),
|
||||
[enumBalancerVariants.mergerInverse]: generateMatrixRotations([0, 1, 0, 1, 1, 0, 0, 1, 0]),
|
||||
[enumBalancerVariants.splitter]: generateMatrixRotations([0, 1, 0, 0, 1, 1, 0, 1, 0]),
|
||||
[enumBalancerVariants.splitterInverse]: generateMatrixRotations([0, 1, 0, 1, 1, 0, 0, 1, 0]),
|
||||
};
|
||||
|
||||
export class MetaBalancerBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("balancer");
|
||||
@@ -37,18 +45,43 @@ export class MetaBalancerBuilding extends MetaBuilding {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotation
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @param {Entity} entity
|
||||
* @returns {Array<number>|null}
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
const matrix = overlayMatrices[variant];
|
||||
if (matrix) {
|
||||
return matrix[rotation];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.balancer);
|
||||
let speedMultiplier = 2;
|
||||
switch (variant) {
|
||||
case enumBalancerVariants.merger:
|
||||
case enumBalancerVariants.mergerInverse:
|
||||
case enumBalancerVariants.splitter:
|
||||
case enumBalancerVariants.splitterInverse:
|
||||
speedMultiplier = 1;
|
||||
}
|
||||
|
||||
const speed =
|
||||
(root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.balancer) / 2) * speedMultiplier;
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#444";
|
||||
return "#555759";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,12 +6,15 @@ import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { T } from "../../translations";
|
||||
import { formatItemsPerSecond } from "../../core/utils";
|
||||
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumMinerVariants = { chainable: "chainable" };
|
||||
|
||||
const overlayMatrix = [1, 1, 1, 1, 0, 1, 1, 1, 1];
|
||||
const overlayMatrix = {
|
||||
[defaultBuildingVariant]: generateMatrixRotations([1, 1, 1, 1, 0, 1, 1, 1, 1]),
|
||||
[enumMinerVariants.chainable]: generateMatrixRotations([0, 1, 0, 1, 1, 1, 1, 1, 1]),
|
||||
};
|
||||
|
||||
export class MetaMinerBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
@@ -50,7 +53,7 @@ export class MetaMinerBuilding extends MetaBuilding {
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
return overlayMatrix;
|
||||
return overlayMatrix[variant][rotation];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formatItemsPerSecond } from "../../core/utils";
|
||||
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { T } from "../../translations";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
@@ -12,6 +12,11 @@ import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
/** @enum {string} */
|
||||
export const enumRotaterVariants = { ccw: "ccw", rotate180: "rotate180" };
|
||||
|
||||
const overlayMatrices = {
|
||||
[defaultBuildingVariant]: generateMatrixRotations([0, 1, 1, 1, 1, 0, 0, 1, 1]),
|
||||
[enumRotaterVariants.ccw]: generateMatrixRotations([1, 1, 0, 0, 1, 1, 1, 1, 0]),
|
||||
};
|
||||
|
||||
export class MetaRotaterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("rotater");
|
||||
@@ -21,6 +26,21 @@ export class MetaRotaterBuilding extends MetaBuilding {
|
||||
return "#7dc6cd";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotation
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @param {Entity} entity
|
||||
* @returns {Array<number>|null}
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
const matrix = overlayMatrices[variant];
|
||||
if (matrix) {
|
||||
return matrix[rotation];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
|
||||
@@ -1,266 +1,268 @@
|
||||
import { Loader } from "../../core/loader";
|
||||
import { enumDirection, Vector, enumAngleToDirection, enumDirectionToVector } from "../../core/vector";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
|
||||
import { T } from "../../translations";
|
||||
|
||||
/** @enum {string} */
|
||||
export const arrayUndergroundRotationVariantToMode = [
|
||||
enumUndergroundBeltMode.sender,
|
||||
enumUndergroundBeltMode.receiver,
|
||||
];
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumUndergroundBeltVariants = { tier2: "tier2" };
|
||||
|
||||
export const enumUndergroundBeltVariantToTier = {
|
||||
[defaultBuildingVariant]: 0,
|
||||
[enumUndergroundBeltVariants.tier2]: 1,
|
||||
};
|
||||
|
||||
const overlayMatrices = [
|
||||
// Sender
|
||||
generateMatrixRotations([1, 1, 1, 0, 1, 0, 0, 1, 0]),
|
||||
|
||||
// Receiver
|
||||
generateMatrixRotations([0, 1, 0, 0, 1, 0, 1, 1, 1]),
|
||||
];
|
||||
|
||||
export class MetaUndergroundBeltBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("underground_belt");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#222";
|
||||
}
|
||||
|
||||
getFlipOrientationAfterPlacement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotation
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
return overlayMatrices[rotationVariant][rotation];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
const rangeTiles =
|
||||
globalConfig.undergroundBeltMaxTilesByTier[enumUndergroundBeltVariantToTier[variant]];
|
||||
|
||||
const beltSpeed = root.hubGoals.getUndergroundBeltBaseSpeed();
|
||||
return [
|
||||
[
|
||||
T.ingame.buildingPlacement.infoTexts.range,
|
||||
T.ingame.buildingPlacement.infoTexts.tiles.replace("<x>", "" + rangeTiles),
|
||||
],
|
||||
[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(beltSpeed)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getAvailableVariants(root) {
|
||||
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_underground_belt_tier_2)) {
|
||||
return [defaultBuildingVariant, enumUndergroundBeltVariants.tier2];
|
||||
}
|
||||
return super.getAvailableVariants(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
getPreviewSprite(rotationVariant, variant) {
|
||||
let suffix = "";
|
||||
if (variant !== defaultBuildingVariant) {
|
||||
suffix = "-" + variant;
|
||||
}
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender:
|
||||
return Loader.getSprite("sprites/buildings/underground_belt_entry" + suffix + ".png");
|
||||
case enumUndergroundBeltMode.receiver:
|
||||
return Loader.getSprite("sprites/buildings/underground_belt_exit" + suffix + ".png");
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
getBlueprintSprite(rotationVariant, variant) {
|
||||
let suffix = "";
|
||||
if (variant !== defaultBuildingVariant) {
|
||||
suffix = "-" + variant;
|
||||
}
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender:
|
||||
return Loader.getSprite("sprites/blueprints/underground_belt_entry" + suffix + ".png");
|
||||
case enumUndergroundBeltMode.receiver:
|
||||
return Loader.getSprite("sprites/blueprints/underground_belt_exit" + suffix + ".png");
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
getSprite(rotationVariant, variant) {
|
||||
return this.getPreviewSprite(rotationVariant, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_tunnel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
// Required, since the item processor needs this.
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(new UndergroundBeltComponent({}));
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should compute the optimal rotation variant on the given tile
|
||||
* @param {object} param0
|
||||
* @param {GameRoot} param0.root
|
||||
* @param {Vector} param0.tile
|
||||
* @param {number} param0.rotation
|
||||
* @param {string} param0.variant
|
||||
* @param {Layer} param0.layer
|
||||
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
|
||||
const searchDirection = enumAngleToDirection[rotation];
|
||||
const searchVector = enumDirectionToVector[searchDirection];
|
||||
const tier = enumUndergroundBeltVariantToTier[variant];
|
||||
|
||||
const targetRotation = (rotation + 180) % 360;
|
||||
const targetSenderRotation = rotation;
|
||||
|
||||
for (
|
||||
let searchOffset = 1;
|
||||
searchOffset <= globalConfig.undergroundBeltMaxTilesByTier[tier];
|
||||
++searchOffset
|
||||
) {
|
||||
tile = tile.addScalars(searchVector.x, searchVector.y);
|
||||
|
||||
/* WIRES: FIXME */
|
||||
const contents = root.map.getTileContent(tile, "regular");
|
||||
if (contents) {
|
||||
const undergroundComp = contents.components.UndergroundBelt;
|
||||
if (undergroundComp && undergroundComp.tier === tier) {
|
||||
const staticComp = contents.components.StaticMapEntity;
|
||||
if (staticComp.rotation === targetRotation) {
|
||||
if (undergroundComp.mode !== enumUndergroundBeltMode.sender) {
|
||||
// If we encounter an underground receiver on our way which is also faced in our direction, we don't accept that
|
||||
break;
|
||||
}
|
||||
return {
|
||||
rotation: targetRotation,
|
||||
rotationVariant: 1,
|
||||
connectedEntities: [contents],
|
||||
};
|
||||
} else if (staticComp.rotation === targetSenderRotation) {
|
||||
// Draw connections to receivers
|
||||
if (undergroundComp.mode === enumUndergroundBeltMode.receiver) {
|
||||
return {
|
||||
rotation: rotation,
|
||||
rotationVariant: 0,
|
||||
connectedEntities: [contents],
|
||||
};
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant, variant) {
|
||||
entity.components.UndergroundBelt.tier = enumUndergroundBeltVariantToTier[variant];
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender: {
|
||||
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.sender;
|
||||
entity.components.ItemEjector.setSlots([]);
|
||||
entity.components.ItemAcceptor.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
case enumUndergroundBeltMode.receiver: {
|
||||
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.receiver;
|
||||
entity.components.ItemAcceptor.setSlots([]);
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.top,
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
import { Loader } from "../../core/loader";
|
||||
import { enumDirection, Vector, enumAngleToDirection, enumDirectionToVector } from "../../core/vector";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
|
||||
import { T } from "../../translations";
|
||||
|
||||
/** @enum {string} */
|
||||
export const arrayUndergroundRotationVariantToMode = [
|
||||
enumUndergroundBeltMode.sender,
|
||||
enumUndergroundBeltMode.receiver,
|
||||
];
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumUndergroundBeltVariants = { tier2: "tier2" };
|
||||
|
||||
export const enumUndergroundBeltVariantToTier = {
|
||||
[defaultBuildingVariant]: 0,
|
||||
[enumUndergroundBeltVariants.tier2]: 1,
|
||||
};
|
||||
|
||||
const colorsByRotationVariant = ["#6d9dff", "#51d723"];
|
||||
|
||||
const overlayMatrices = [
|
||||
// Sender
|
||||
generateMatrixRotations([1, 1, 1, 0, 1, 0, 0, 1, 0]),
|
||||
|
||||
// Receiver
|
||||
generateMatrixRotations([0, 1, 0, 0, 1, 0, 1, 1, 1]),
|
||||
];
|
||||
|
||||
export class MetaUndergroundBeltBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("underground_belt");
|
||||
}
|
||||
|
||||
getSilhouetteColor(variant, rotationVariant) {
|
||||
return colorsByRotationVariant[rotationVariant];
|
||||
}
|
||||
|
||||
getFlipOrientationAfterPlacement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotation
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
return overlayMatrices[rotationVariant][rotation];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
const rangeTiles =
|
||||
globalConfig.undergroundBeltMaxTilesByTier[enumUndergroundBeltVariantToTier[variant]];
|
||||
|
||||
const beltSpeed = root.hubGoals.getUndergroundBeltBaseSpeed();
|
||||
return [
|
||||
[
|
||||
T.ingame.buildingPlacement.infoTexts.range,
|
||||
T.ingame.buildingPlacement.infoTexts.tiles.replace("<x>", "" + rangeTiles),
|
||||
],
|
||||
[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(beltSpeed)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getAvailableVariants(root) {
|
||||
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_underground_belt_tier_2)) {
|
||||
return [defaultBuildingVariant, enumUndergroundBeltVariants.tier2];
|
||||
}
|
||||
return super.getAvailableVariants(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
getPreviewSprite(rotationVariant, variant) {
|
||||
let suffix = "";
|
||||
if (variant !== defaultBuildingVariant) {
|
||||
suffix = "-" + variant;
|
||||
}
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender:
|
||||
return Loader.getSprite("sprites/buildings/underground_belt_entry" + suffix + ".png");
|
||||
case enumUndergroundBeltMode.receiver:
|
||||
return Loader.getSprite("sprites/buildings/underground_belt_exit" + suffix + ".png");
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
getBlueprintSprite(rotationVariant, variant) {
|
||||
let suffix = "";
|
||||
if (variant !== defaultBuildingVariant) {
|
||||
suffix = "-" + variant;
|
||||
}
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender:
|
||||
return Loader.getSprite("sprites/blueprints/underground_belt_entry" + suffix + ".png");
|
||||
case enumUndergroundBeltMode.receiver:
|
||||
return Loader.getSprite("sprites/blueprints/underground_belt_exit" + suffix + ".png");
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
getSprite(rotationVariant, variant) {
|
||||
return this.getPreviewSprite(rotationVariant, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_tunnel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
// Required, since the item processor needs this.
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(new UndergroundBeltComponent({}));
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should compute the optimal rotation variant on the given tile
|
||||
* @param {object} param0
|
||||
* @param {GameRoot} param0.root
|
||||
* @param {Vector} param0.tile
|
||||
* @param {number} param0.rotation
|
||||
* @param {string} param0.variant
|
||||
* @param {Layer} param0.layer
|
||||
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
|
||||
const searchDirection = enumAngleToDirection[rotation];
|
||||
const searchVector = enumDirectionToVector[searchDirection];
|
||||
const tier = enumUndergroundBeltVariantToTier[variant];
|
||||
|
||||
const targetRotation = (rotation + 180) % 360;
|
||||
const targetSenderRotation = rotation;
|
||||
|
||||
for (
|
||||
let searchOffset = 1;
|
||||
searchOffset <= globalConfig.undergroundBeltMaxTilesByTier[tier];
|
||||
++searchOffset
|
||||
) {
|
||||
tile = tile.addScalars(searchVector.x, searchVector.y);
|
||||
|
||||
/* WIRES: FIXME */
|
||||
const contents = root.map.getTileContent(tile, "regular");
|
||||
if (contents) {
|
||||
const undergroundComp = contents.components.UndergroundBelt;
|
||||
if (undergroundComp && undergroundComp.tier === tier) {
|
||||
const staticComp = contents.components.StaticMapEntity;
|
||||
if (staticComp.rotation === targetRotation) {
|
||||
if (undergroundComp.mode !== enumUndergroundBeltMode.sender) {
|
||||
// If we encounter an underground receiver on our way which is also faced in our direction, we don't accept that
|
||||
break;
|
||||
}
|
||||
return {
|
||||
rotation: targetRotation,
|
||||
rotationVariant: 1,
|
||||
connectedEntities: [contents],
|
||||
};
|
||||
} else if (staticComp.rotation === targetSenderRotation) {
|
||||
// Draw connections to receivers
|
||||
if (undergroundComp.mode === enumUndergroundBeltMode.receiver) {
|
||||
return {
|
||||
rotation: rotation,
|
||||
rotationVariant: 0,
|
||||
connectedEntities: [contents],
|
||||
};
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant, variant) {
|
||||
entity.components.UndergroundBelt.tier = enumUndergroundBeltVariantToTier[variant];
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender: {
|
||||
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.sender;
|
||||
entity.components.ItemEjector.setSlots([]);
|
||||
entity.components.ItemAcceptor.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
case enumUndergroundBeltMode.receiver: {
|
||||
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.receiver;
|
||||
entity.components.ItemAcceptor.setSlots([]);
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.top,
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
|
||||
this.root.hud.signals.buildingsSelectedForCopy.add(this.abortPlacement, this);
|
||||
this.root.hud.signals.pasteBlueprintRequested.add(this.abortPlacement, this);
|
||||
this.root.signals.storyGoalCompleted.add(() => this.signals.variantChanged.dispatch());
|
||||
this.root.signals.storyGoalCompleted.add(() => this.currentMetaBuilding.set(null));
|
||||
this.root.signals.upgradePurchased.add(() => this.signals.variantChanged.dispatch());
|
||||
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
||||
|
||||
|
||||
@@ -170,7 +170,10 @@ export class MapChunkView extends MapChunk {
|
||||
);
|
||||
}
|
||||
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor();
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor(
|
||||
data.variant,
|
||||
data.rotationVariant
|
||||
);
|
||||
for (let dx = 0; dx < 3; ++dx) {
|
||||
for (let dy = 0; dy < 3; ++dy) {
|
||||
const isFilled = overlayMatrix[dx + dy * 3];
|
||||
@@ -187,7 +190,10 @@ export class MapChunkView extends MapChunk {
|
||||
|
||||
continue;
|
||||
} else {
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor();
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor(
|
||||
data.variant,
|
||||
data.rotationVariant
|
||||
);
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
@@ -256,7 +262,8 @@ export class MapChunkView extends MapChunk {
|
||||
data.variant,
|
||||
entity
|
||||
);
|
||||
context.fillStyle = overrideColor || metaBuilding.getSilhouetteColor();
|
||||
context.fillStyle =
|
||||
overrideColor || metaBuilding.getSilhouetteColor(data.variant, data.rotationVariant);
|
||||
if (overlayMatrix) {
|
||||
for (let dx = 0; dx < 3; ++dx) {
|
||||
for (let dy = 0; dy < 3; ++dy) {
|
||||
|
||||
@@ -1,273 +1,275 @@
|
||||
import { Loader } from "../core/loader";
|
||||
import { AtlasSprite } from "../core/sprites";
|
||||
import { Vector } from "../core/vector";
|
||||
import { SOUNDS } from "../platform/sound";
|
||||
import { StaticMapEntityComponent } from "./components/static_map_entity";
|
||||
import { Entity } from "./entity";
|
||||
import { GameRoot } from "./root";
|
||||
import { getCodeFromBuildingData } from "./building_codes";
|
||||
|
||||
export const defaultBuildingVariant = "default";
|
||||
|
||||
export class MetaBuilding {
|
||||
/**
|
||||
*
|
||||
* @param {string} id Building id
|
||||
*/
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of this building
|
||||
*/
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edit layer of the building
|
||||
* @returns {Layer}
|
||||
*/
|
||||
getLayer() {
|
||||
return "regular";
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the dimensions of the building
|
||||
*/
|
||||
getDimensions(variant = defaultBuildingVariant) {
|
||||
return new Vector(1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the building has the direction lock switch available
|
||||
*/
|
||||
getHasDirectionLockAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to stay in placement mode after having placed a building
|
||||
*/
|
||||
getStayInPlacementMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can return a special interlaved 9 elements overlay matrix for rendering
|
||||
* @param {number} rotation
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @param {Entity} entity
|
||||
* @returns {Array<number>|null}
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return additional statistics about this building
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building can get replaced
|
||||
*/
|
||||
getIsReplaceable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to flip the orientation after a building has been placed - useful
|
||||
* for tunnels.
|
||||
*/
|
||||
getFlipOrientationAfterPlacement() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to show a preview of the wires layer when placing the building
|
||||
*/
|
||||
getShowWiresLayerPreview() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to rotate automatically in the dragging direction while placing
|
||||
* @param {string} variant
|
||||
*/
|
||||
getRotateAutomaticallyWhilePlacing(variant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is removable
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsRemovable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the placement sound
|
||||
* @returns {string}
|
||||
*/
|
||||
getPlacementSound() {
|
||||
return SOUNDS.placeBuilding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getAvailableVariants(root) {
|
||||
return [defaultBuildingVariant];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preview sprite
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getPreviewSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
|
||||
return Loader.getSprite(
|
||||
"sprites/buildings/" +
|
||||
this.id +
|
||||
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||
".png"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sprite for blueprints
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getBlueprintSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
|
||||
return Loader.getSprite(
|
||||
"sprites/blueprints/" +
|
||||
this.id +
|
||||
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||
".png"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is rotateable
|
||||
* @param {string} variant
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsRotateable(variant) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is unlocked for the given game
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return a silhouette color for the map overview or null if not set
|
||||
*/
|
||||
getSilhouetteColor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return false if the pins are already included in the sprite of the building
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getRenderPins() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity without placing it
|
||||
* @param {object} param0
|
||||
* @param {GameRoot} param0.root
|
||||
* @param {Vector} param0.origin Origin tile
|
||||
* @param {number=} param0.rotation Rotation
|
||||
* @param {number} param0.originalRotation Original Rotation
|
||||
* @param {number} param0.rotationVariant Rotation variant
|
||||
* @param {string} param0.variant
|
||||
*/
|
||||
createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) {
|
||||
const entity = new Entity(root);
|
||||
entity.layer = this.getLayer();
|
||||
entity.addComponent(
|
||||
new StaticMapEntityComponent({
|
||||
origin: new Vector(origin.x, origin.y),
|
||||
rotation,
|
||||
originalRotation,
|
||||
tileSize: this.getDimensions(variant).copy(),
|
||||
code: getCodeFromBuildingData(this, variant, rotationVariant),
|
||||
})
|
||||
);
|
||||
this.setupEntityComponents(entity, root);
|
||||
this.updateVariants(entity, rotationVariant, variant);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite for a given variant
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getSprite(rotationVariant, variant) {
|
||||
return Loader.getSprite(
|
||||
"sprites/buildings/" +
|
||||
this.id +
|
||||
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||
".png"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should compute the optimal rotation variant on the given tile
|
||||
* @param {object} param0
|
||||
* @param {GameRoot} param0.root
|
||||
* @param {Vector} param0.tile
|
||||
* @param {number} param0.rotation
|
||||
* @param {string} param0.variant
|
||||
* @param {Layer} param0.layer
|
||||
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
|
||||
if (!this.getIsRotateable(variant)) {
|
||||
return {
|
||||
rotation: 0,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Should update the entity to match the given variants
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant, variant) {}
|
||||
|
||||
// PRIVATE INTERFACE
|
||||
|
||||
/**
|
||||
* Should setup the entity components
|
||||
* @param {Entity} entity
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
setupEntityComponents(entity, root) {
|
||||
abstract;
|
||||
}
|
||||
}
|
||||
import { Loader } from "../core/loader";
|
||||
import { AtlasSprite } from "../core/sprites";
|
||||
import { Vector } from "../core/vector";
|
||||
import { SOUNDS } from "../platform/sound";
|
||||
import { StaticMapEntityComponent } from "./components/static_map_entity";
|
||||
import { Entity } from "./entity";
|
||||
import { GameRoot } from "./root";
|
||||
import { getCodeFromBuildingData } from "./building_codes";
|
||||
|
||||
export const defaultBuildingVariant = "default";
|
||||
|
||||
export class MetaBuilding {
|
||||
/**
|
||||
*
|
||||
* @param {string} id Building id
|
||||
*/
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of this building
|
||||
*/
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edit layer of the building
|
||||
* @returns {Layer}
|
||||
*/
|
||||
getLayer() {
|
||||
return "regular";
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the dimensions of the building
|
||||
*/
|
||||
getDimensions(variant = defaultBuildingVariant) {
|
||||
return new Vector(1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the building has the direction lock switch available
|
||||
*/
|
||||
getHasDirectionLockAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to stay in placement mode after having placed a building
|
||||
*/
|
||||
getStayInPlacementMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can return a special interlaved 9 elements overlay matrix for rendering
|
||||
* @param {number} rotation
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @param {Entity} entity
|
||||
* @returns {Array<number>|null}
|
||||
*/
|
||||
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return additional statistics about this building
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building can get replaced
|
||||
*/
|
||||
getIsReplaceable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to flip the orientation after a building has been placed - useful
|
||||
* for tunnels.
|
||||
*/
|
||||
getFlipOrientationAfterPlacement() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to show a preview of the wires layer when placing the building
|
||||
*/
|
||||
getShowWiresLayerPreview() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to rotate automatically in the dragging direction while placing
|
||||
* @param {string} variant
|
||||
*/
|
||||
getRotateAutomaticallyWhilePlacing(variant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is removable
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsRemovable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the placement sound
|
||||
* @returns {string}
|
||||
*/
|
||||
getPlacementSound() {
|
||||
return SOUNDS.placeBuilding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getAvailableVariants(root) {
|
||||
return [defaultBuildingVariant];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preview sprite
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getPreviewSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
|
||||
return Loader.getSprite(
|
||||
"sprites/buildings/" +
|
||||
this.id +
|
||||
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||
".png"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sprite for blueprints
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getBlueprintSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
|
||||
return Loader.getSprite(
|
||||
"sprites/blueprints/" +
|
||||
this.id +
|
||||
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||
".png"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is rotateable
|
||||
* @param {string} variant
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsRotateable(variant) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is unlocked for the given game
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return a silhouette color for the map overview or null if not set
|
||||
* @param {string} variant
|
||||
* @param {number} rotationVariant
|
||||
*/
|
||||
getSilhouetteColor(variant, rotationVariant) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return false if the pins are already included in the sprite of the building
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getRenderPins() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity without placing it
|
||||
* @param {object} param0
|
||||
* @param {GameRoot} param0.root
|
||||
* @param {Vector} param0.origin Origin tile
|
||||
* @param {number=} param0.rotation Rotation
|
||||
* @param {number} param0.originalRotation Original Rotation
|
||||
* @param {number} param0.rotationVariant Rotation variant
|
||||
* @param {string} param0.variant
|
||||
*/
|
||||
createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) {
|
||||
const entity = new Entity(root);
|
||||
entity.layer = this.getLayer();
|
||||
entity.addComponent(
|
||||
new StaticMapEntityComponent({
|
||||
origin: new Vector(origin.x, origin.y),
|
||||
rotation,
|
||||
originalRotation,
|
||||
tileSize: this.getDimensions(variant).copy(),
|
||||
code: getCodeFromBuildingData(this, variant, rotationVariant),
|
||||
})
|
||||
);
|
||||
this.setupEntityComponents(entity, root);
|
||||
this.updateVariants(entity, rotationVariant, variant);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite for a given variant
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getSprite(rotationVariant, variant) {
|
||||
return Loader.getSprite(
|
||||
"sprites/buildings/" +
|
||||
this.id +
|
||||
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||
".png"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should compute the optimal rotation variant on the given tile
|
||||
* @param {object} param0
|
||||
* @param {GameRoot} param0.root
|
||||
* @param {Vector} param0.tile
|
||||
* @param {number} param0.rotation
|
||||
* @param {string} param0.variant
|
||||
* @param {Layer} param0.layer
|
||||
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
|
||||
if (!this.getIsRotateable(variant)) {
|
||||
return {
|
||||
rotation: 0,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Should update the entity to match the given variants
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant, variant) {}
|
||||
|
||||
// PRIVATE INTERFACE
|
||||
|
||||
/**
|
||||
* Should setup the entity components
|
||||
* @param {Entity} entity
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
setupEntityComponents(entity, root) {
|
||||
abstract;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,10 @@ export function initBuildingCodesAfterResourcesLoaded() {
|
||||
variant.rotationVariant,
|
||||
variant.variant
|
||||
);
|
||||
variant.silhouetteColor = variant.metaInstance.getSilhouetteColor();
|
||||
variant.silhouetteColor = variant.metaInstance.getSilhouetteColor(
|
||||
variant.variant,
|
||||
variant.rotationVariant
|
||||
);
|
||||
}
|
||||
|
||||
// Update caches
|
||||
|
||||
@@ -5,7 +5,6 @@ import { BaseItem } from "../base_item";
|
||||
import { MinerComponent } from "../components/miner";
|
||||
import { Entity } from "../entity";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { statisticsUnitsSeconds } from "../hud/parts/statistics_handle";
|
||||
import { MapChunkView } from "../map_chunk_view";
|
||||
|
||||
export class MinerSystem extends GameSystemWithFilter {
|
||||
|
||||
@@ -45,7 +45,7 @@ export const enumHubGoalRewardsToContentUnlocked = {
|
||||
[enumHubGoalRewards.reward_cutter_quad]: typed([[MetaCutterBuilding, enumCutterVariants.quad]]),
|
||||
[enumHubGoalRewards.reward_painter_double]: typed([[MetaPainterBuilding, enumPainterVariants.double]]),
|
||||
[enumHubGoalRewards.reward_painter_quad]: typed([[MetaPainterBuilding, enumPainterVariants.quad]]),
|
||||
[enumHubGoalRewards.reward_storage]: typed([[MetaStorageBuilding]]),
|
||||
[enumHubGoalRewards.reward_storage]: typed([[MetaStorageBuilding, defaultBuildingVariant]]),
|
||||
|
||||
[enumHubGoalRewards.reward_belt_reader]: typed([[MetaReaderBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_display]: typed([[MetaDisplayBuilding, defaultBuildingVariant]]),
|
||||
|
||||
Reference in New Issue
Block a user