Skip to content

Commit

Permalink
feat: add pride & country skins, improve ux (#146)
Browse files Browse the repository at this point in the history
* feat: add pride skins, more countries

* feat: players start with 100 cash

* feat: show skin name in alert, improve colors
  • Loading branch information
littensy authored Oct 2, 2023
1 parent 51f09e3 commit 8fd8c42
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 42 deletions.
4 changes: 2 additions & 2 deletions src/client/app/components/alerts/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export function Alert({ alert, index }: AlertProps) {

const style = useMemo(() => {
const highlight = composeBindings(hover, transition, (a, b) => a * b);
const background = darken(alert.color.Lerp(palette.base, 0.25), 0.5);
const backgroundSecondary = darken(alert.colorSecondary?.Lerp(palette.base, 0.25) || palette.white, 0.5);
const background = darken(alert.color.Lerp(palette.base, 0.25), 0.8);
const backgroundSecondary = darken(alert.colorSecondary?.Lerp(palette.base, 0.25) || palette.white, 0.8);
const message = brightenIfDark(alert.colorMessage || alert.color);

return { highlight, background, backgroundSecondary, message };
Expand Down
40 changes: 27 additions & 13 deletions src/client/app/components/menu/skins/act-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Text } from "client/app/common/text";
import { useMotion, useRem } from "client/app/hooks";
import { composeBindings } from "client/app/utils/compose-bindings";
import { fonts } from "client/app/utils/fonts";
import { formatInteger } from "client/app/utils/format-integer";
import { springs } from "client/app/utils/springs";
import { selectMenuCurrentSkin } from "client/store/menu";
import { sounds } from "shared/assets";
Expand All @@ -16,15 +17,25 @@ import { palette } from "shared/data/palette";
import { findSnakeSkin } from "shared/data/skins";
import { remotes } from "shared/remotes";
import { RANDOM_SKIN, selectCurrentPlayerSkin, selectPlayerBalance, selectPlayerSkins } from "shared/store/saves";
import { brighten } from "shared/utils/color-utils";
import { darken } from "shared/utils/color-utils";

interface Status {
readonly variant: "buy" | "not-enough-money" | "wear" | "wearing" | "none";
readonly price?: number;
}

const darkGreen = brighten(palette.green, -3);
const darkRed = brighten(palette.red, -3);
const darkGreen = darken(palette.green, 0.5, 0.5);
const darkRed = darken(palette.red, 0.25, 0.5);
const darkBlue = darken(palette.blue, 0.25, 0.5);
const darkPeach = darken(palette.peach, 0.25, 0.5);

function stylize(text: unknown, color: Color3) {
if (text === `"${RANDOM_SKIN}"`) {
text = '"random"';
}

return `<font color="#${color.ToHex()}">${text}</font>`;
}

function getStatus(equipped: string, current: string, inventory: readonly string[] = [], balance = 0): Status {
const equippedSkin = findSnakeSkin(equipped);
Expand All @@ -47,11 +58,11 @@ function getStatus(equipped: string, current: string, inventory: readonly string

export function ActButton() {
const rem = useRem();
const equipped = useSelectorCreator(selectCurrentPlayerSkin, LOCAL_USER) ?? RANDOM_SKIN;
const current = useSelector(selectMenuCurrentSkin);
const equippedSkin = useSelectorCreator(selectCurrentPlayerSkin, LOCAL_USER) ?? RANDOM_SKIN;
const currentSkin = useSelector(selectMenuCurrentSkin);
const inventory = useSelectorCreator(selectPlayerSkins, LOCAL_USER);
const balance = useSelectorCreator(selectPlayerBalance, LOCAL_USER);
const status = getStatus(equipped, current, inventory, balance);
const status = getStatus(equippedSkin, currentSkin, inventory, balance);

const [primary, primaryMotion] = useMotion(new Color3());
const [secondary, secondaryMotion] = useMotion(new Color3());
Expand All @@ -75,14 +86,14 @@ export function ActButton() {
gradientSpinMotion.spring(gradientSpin.getValue() + 180, springs.molasses);

if (status.variant === "buy") {
remotes.save.buySkin.fire(current);
remotes.save.buySkin.fire(currentSkin);
} else if (status.variant === "wear") {
remotes.save.setSkin.fire(current);
remotes.save.setSkin.fire(currentSkin);
} else if (status.variant === "not-enough-money") {
sendAlert({
emoji: "🚨",
color: palette.red,
message: `Sorry, you cannot afford the <font color="#fff">${current}</font> skin yet.`,
message: `Sorry, you cannot afford the ${stylize(currentSkin, palette.white)} skin yet.`,
sound: sounds.alert_bad,
});
}
Expand Down Expand Up @@ -112,13 +123,16 @@ export function ActButton() {

const text =
status.variant === "buy"
? `💵 Buy for <font color="#${darkGreen.ToHex()}">$${status.price}</font>`
? `💵 Buy ${stylize(`"${currentSkin}"`, darkGreen)} for ${stylize(
"$" + formatInteger(status.price),
darkGreen,
)}`
: status.variant === "wear"
? "🎨 Wear"
? `🎨 Wear ${stylize(`"${currentSkin}"`, darkBlue)}`
: status.variant === "wearing"
? "🎨 Wearing"
? `🎨 Wearing ${stylize(`"${currentSkin}"`, darkPeach)}`
: status.variant === "not-enough-money"
? `🔒 Costs <font color="#${darkRed.ToHex()}">$${status.price}</font>`
? `🔒 ${stylize(`"${currentSkin}"`, darkRed)} costs ${stylize("$" + formatInteger(status.price), darkRed)}`
: "🔒 Locked";

return (
Expand Down
4 changes: 2 additions & 2 deletions src/client/app/components/menu/skins/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function usePalette(id: string, shuffle?: readonly string[]): SnakePalett

return {
skin,
primary: skin.primary || darken(skin.tint[0], 0.5, 0.5),
secondary: skin.secondary || darken(skin.tint[0], 0.7, 0.5),
primary: skin.primary || darken(skin.tint[0], 0.5, 0.4),
secondary: skin.secondary || darken(skin.tint[0], 0.7, 0.4),
};
}
7 changes: 3 additions & 4 deletions src/client/app/stories/components/skins.story.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { hoarcekat, useMountEffect } from "@rbxts/pretty-react-hooks";
import Roact from "@rbxts/roact";
import { Alerts } from "client/app/components/alerts";
import { Menu } from "client/app/components/menu";
import { World } from "client/app/components/world";
import { RootProvider } from "client/app/providers/root-provider";
Expand All @@ -14,16 +15,14 @@ export = hoarcekat(() => {

useMountEffect(() => {
store.setMenuPage("skins");
store.setPlayerSave(LOCAL_USER, {
...defaultPlayerSave,
balance: 45,
});
store.setPlayerSave(LOCAL_USER, defaultPlayerSave);
});

return (
<RootProvider>
<World />
<Menu />
<Alerts />
</RootProvider>
);
});
2 changes: 1 addition & 1 deletion src/client/app/utils/format-integer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Reformat a number to a string with a thousands separator.
*/
export function formatInteger(value: string | number) {
export function formatInteger(value: unknown) {
return tostring(value).reverse().gsub("%d%d%d", "%1,")[0].reverse().gsub("^,", "")[0];
}
2 changes: 1 addition & 1 deletion src/server/players/services/remotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export async function initRemoteService() {
colorMessage: skin?.primary || skin?.tint[0] || palette.mauve,
message:
skinId === RANDOM_SKIN
? "You are now wearing a random skin!"
? 'You are now wearing a <font color="#fff">random</font> skin!'
: `You are now wearing the <font color="#fff">${skinId}</font> skin!`,
});
} else {
Expand Down
Loading

0 comments on commit 8fd8c42

Please sign in to comment.