Skip to content

Commit 983e77a

Browse files
committed
feat: Football Gate
By @oobjectt billsonnn/nitro-react#145
1 parent 6c48eea commit 983e77a

8 files changed

Lines changed: 192 additions & 37 deletions

File tree

apps/frontend/src/components/avatar-editor/AvatarEditorView.tsx

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
GetWardrobeMessageComposer,
55
IAvatarFigureContainer,
66
ILinkEventTracker,
7+
SetClothingChangeDataMessageComposer,
78
UserFigureComposer,
89
UserWardrobePageEvent,
910
} from "@nitro/renderer";
@@ -47,6 +48,8 @@ import {AvatarEditorWardrobeView} from "./views/AvatarEditorWardrobeView";
4748

4849
const DEFAULT_MALE_FIGURE: string = "hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007";
4950
const DEFAULT_FEMALE_FIGURE: string = "hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68";
51+
const DEFAULT_MALE_FOOTBALL_GATE: string = "ch-3109-92-1408.lg-3116-82-1408.sh-3115-1408-1408";
52+
const DEFAULT_FEMALE_FOOTBALL_GATE: string = "ch-3112-1408-1408.lg-3116-71-1408.sh-3115-1408-1408";
5053

5154
export const AvatarEditorView: FC<{}> = props => {
5255
const [isVisible, setIsVisible] = useState(false);
@@ -62,9 +65,17 @@ export const AvatarEditorView: FC<{}> = props => {
6265
const [lastGender, setLastGender] = useState<string>(null);
6366
const [needsReset, setNeedsReset] = useState(true);
6467
const [isInitalized, setIsInitalized] = useState(false);
68+
const [genderFootballGate, setGenderFootballGate] = useState<string>(null);
69+
const [objectFootballGate, setObjectFootballGate] = useState<number>(null);
6570

6671
const maxWardrobeSlots = useMemo(() => GetConfiguration<number>("avatar.wardrobe.max.slots", 10), []);
6772

73+
const onClose = () => {
74+
setGenderFootballGate(null);
75+
setObjectFootballGate(null);
76+
setIsVisible(false);
77+
};
78+
6879
useMessageEvent<FigureSetIdsMessageEvent>(FigureSetIdsMessageEvent, event => {
6980
const parser = event.getParser();
7081

@@ -105,13 +116,18 @@ export const AvatarEditorView: FC<{}> = props => {
105116
const resetCategories = useCallback(() => {
106117
const categories = new Map();
107118

108-
categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel());
109-
categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel());
110-
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
111-
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
119+
if (!genderFootballGate) {
120+
categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel());
121+
categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel());
122+
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
123+
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
124+
} else {
125+
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
126+
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
127+
}
112128

113129
setCategories(categories);
114-
}, []);
130+
}, [genderFootballGate]);
115131

116132
const setupFigures = useCallback(() => {
117133
const figures: Map<string, FigureData> = new Map();
@@ -167,12 +183,14 @@ export const AvatarEditorView: FC<{}> = props => {
167183
resetCategories();
168184
return;
169185
case AvatarEditorAction.ACTION_SAVE:
170-
SendMessageComposer(new UserFigureComposer(figureData.gender, figureData.getFigureString()));
171-
setIsVisible(false);
186+
!genderFootballGate
187+
? SendMessageComposer(new UserFigureComposer(figureData.gender, figureData.getFigureString()))
188+
: SendMessageComposer(new SetClothingChangeDataMessageComposer(objectFootballGate, genderFootballGate, figureData.getFigureString()));
189+
onClose();
172190
return;
173191
}
174192
},
175-
[figureData, lastFigure, lastGender, figureSetIds, loadAvatarInEditor, resetCategories]
193+
[loadAvatarInEditor, figureData, resetCategories, lastFigure, lastGender, figureSetIds, genderFootballGate, objectFootballGate]
176194
);
177195

178196
const setGender = useCallback(
@@ -189,6 +207,9 @@ export const AvatarEditorView: FC<{}> = props => {
189207
linkReceived: (url: string) => {
190208
const parts = url.split("/");
191209

210+
setGenderFootballGate(parts[2] ? parts[2] : null);
211+
setObjectFootballGate(parts[3] ? Number(parts[3]) : null);
212+
192213
if (parts.length < 2) return;
193214

194215
switch (parts[1]) {
@@ -231,8 +252,8 @@ export const AvatarEditorView: FC<{}> = props => {
231252
useEffect(() => {
232253
if (!categories) return;
233254

234-
selectCategory(AvatarEditorFigureCategory.GENERIC);
235-
}, [categories, selectCategory]);
255+
selectCategory(!genderFootballGate ? AvatarEditorFigureCategory.GENERIC : AvatarEditorFigureCategory.TORSO);
256+
}, [categories, genderFootballGate, selectCategory]);
236257

237258
useEffect(() => {
238259
if (!figureData) return;
@@ -271,9 +292,22 @@ export const AvatarEditorView: FC<{}> = props => {
271292
useEffect(() => {
272293
if (!isVisible || !isInitalized || !needsReset) return;
273294

274-
loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender);
295+
loadAvatarInEditor(
296+
!genderFootballGate ? GetSessionDataManager().figure : genderFootballGate === FigureData.MALE ? DEFAULT_MALE_FOOTBALL_GATE : DEFAULT_FEMALE_FOOTBALL_GATE,
297+
!genderFootballGate ? GetSessionDataManager().gender : genderFootballGate
298+
);
275299
setNeedsReset(false);
276-
}, [isVisible, isInitalized, needsReset, loadAvatarInEditor]);
300+
}, [isVisible, isInitalized, needsReset, loadAvatarInEditor, genderFootballGate]);
301+
302+
useEffect(() =>
303+
// This is so when you have the look editor open and you change the mode to Boy or Girl
304+
{
305+
if (!isVisible) return;
306+
307+
return () => {
308+
setNeedsReset(true);
309+
};
310+
}, [isVisible, genderFootballGate]);
277311

278312
useEffect(() => {
279313
if (isVisible) return;
@@ -287,7 +321,10 @@ export const AvatarEditorView: FC<{}> = props => {
287321

288322
return (
289323
<NitroCardView uniqueKey="avatar-editor" className="nitro-avatar-editor">
290-
<NitroCardHeaderView headerText={LocalizeText("avatareditor.title")} onCloseClick={event => setIsVisible(false)} />
324+
<NitroCardHeaderView
325+
headerText={!genderFootballGate ? LocalizeText("avatareditor.title") : LocalizeText("widget.furni.clothingchange.editor.title")}
326+
onCloseClick={onClose}
327+
/>
291328
<NitroCardTabsView>
292329
{categories &&
293330
categories.size > 0 &&
@@ -300,14 +337,23 @@ export const AvatarEditorView: FC<{}> = props => {
300337
</NitroCardTabsItemView>
301338
);
302339
})}
303-
<NitroCardTabsItemView isActive={isWardrobeVisible} onClick={event => setIsWardrobeVisible(true)}>
304-
{LocalizeText("avatareditor.category.wardrobe")}
305-
</NitroCardTabsItemView>
340+
{!genderFootballGate && (
341+
<NitroCardTabsItemView isActive={isWardrobeVisible} onClick={event => setIsWardrobeVisible(true)}>
342+
{LocalizeText("avatareditor.category.wardrobe")}
343+
</NitroCardTabsItemView>
344+
)}
306345
</NitroCardTabsView>
307346
<NitroCardContentView>
308347
<Grid>
309348
<Column size={9} overflow="hidden">
310-
{activeCategory && !isWardrobeVisible && <AvatarEditorModelView model={activeCategory} gender={figureData.gender} setGender={setGender} />}
349+
{activeCategory && !isWardrobeVisible && (
350+
<AvatarEditorModelView
351+
model={activeCategory}
352+
gender={figureData.gender}
353+
isFromFootballGate={!genderFootballGate ? false : true}
354+
setGender={setGender}
355+
/>
356+
)}
311357
{isWardrobeVisible && (
312358
<AvatarEditorWardrobeView
313359
figureData={figureData}
@@ -320,17 +366,19 @@ export const AvatarEditorView: FC<{}> = props => {
320366
<Column size={3} overflow="hidden">
321367
<AvatarEditorFigurePreviewView figureData={figureData} />
322368
<Column grow gap={1}>
323-
<ButtonGroup>
324-
<Button variant="secondary" onClick={event => processAction(AvatarEditorAction.ACTION_RESET)}>
325-
<FaUndo className="fa-icon" />
326-
</Button>
327-
<Button variant="secondary" onClick={event => processAction(AvatarEditorAction.ACTION_CLEAR)}>
328-
<FaTrash className="fa-icon" />
329-
</Button>
330-
<Button variant="secondary" onClick={event => processAction(AvatarEditorAction.ACTION_RANDOMIZE)}>
331-
<FaDice className="fa-icon" />
332-
</Button>
333-
</ButtonGroup>
369+
{!genderFootballGate && (
370+
<ButtonGroup>
371+
<Button variant="secondary" onClick={event => processAction(AvatarEditorAction.ACTION_RESET)}>
372+
<FaUndo className="fa-icon" />
373+
</Button>
374+
<Button variant="secondary" onClick={event => processAction(AvatarEditorAction.ACTION_CLEAR)}>
375+
<FaTrash className="fa-icon" />
376+
</Button>
377+
<Button variant="secondary" onClick={event => processAction(AvatarEditorAction.ACTION_RANDOMIZE)}>
378+
<FaDice className="fa-icon" />
379+
</Button>
380+
</ButtonGroup>
381+
)}
334382
<Button className="w-100" variant="success" onClick={event => processAction(AvatarEditorAction.ACTION_SAVE)}>
335383
{LocalizeText("avatareditor.save")}
336384
</Button>
@@ -341,3 +389,4 @@ export const AvatarEditorView: FC<{}> = props => {
341389
</NitroCardView>
342390
);
343391
};
392+

apps/frontend/src/components/avatar-editor/views/AvatarEditorModelView.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
import {Dispatch, FC, SetStateAction, useCallback, useEffect, useState} from "react";
1+
import {FC, useCallback, useEffect, useState} from "react";
22

33
import {CategoryData, FigureData, IAvatarEditorCategoryModel} from "../../../api";
44
import {Column, Flex, Grid} from "../../../common";
55
import {AvatarEditorIcon} from "./AvatarEditorIcon";
66
import {AvatarEditorFigureSetView} from "./figure-set/AvatarEditorFigureSetView";
77
import {AvatarEditorPaletteSetView} from "./palette-set/AvatarEditorPaletteSetView";
88

9+
const CATEGORY_FOOTBALL_GATE = ["ch", "cp", "lg", "sh"];
10+
911
export interface AvatarEditorModelViewProps {
1012
model: IAvatarEditorCategoryModel;
1113
gender: string;
12-
setGender: Dispatch<SetStateAction<string>>;
14+
isFromFootballGate: boolean;
15+
setGender: (gender: string) => void;
1316
}
1417

1518
export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props => {
16-
const {model = null, gender = null, setGender = null} = props;
19+
const {model = null, gender = null, isFromFootballGate = false, setGender = null} = props;
1720
const [activeCategory, setActiveCategory] = useState<CategoryData>(null);
1821
const [maxPaletteCount, setMaxPaletteCount] = useState(1);
1922

@@ -70,14 +73,16 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props => {
7073
const category = model.categories.get(name);
7174

7275
return (
73-
<Flex center pointer key={name} className="category-item" onClick={event => selectCategory(name)}>
74-
<AvatarEditorIcon icon={category.name} selected={activeCategory === category} />
75-
</Flex>
76+
(!isFromFootballGate || (isFromFootballGate && CATEGORY_FOOTBALL_GATE.includes(category.name))) && (
77+
<Flex key={category.name} center pointer className="category-item" onClick={event => selectCategory(name)}>
78+
<AvatarEditorIcon icon={category.name} selected={activeCategory === category} />
79+
</Flex>
80+
)
7681
);
7782
})}
7883
</Column>
7984
<Column size={5} overflow="hidden">
80-
<AvatarEditorFigureSetView model={model} category={activeCategory} setMaxPaletteCount={setMaxPaletteCount} />
85+
<AvatarEditorFigureSetView model={model} category={activeCategory} isFromFootballGate={isFromFootballGate} setMaxPaletteCount={setMaxPaletteCount} />
8186
</Column>
8287
<Column size={5} overflow="hidden">
8388
{maxPaletteCount >= 1 && (
@@ -90,3 +95,4 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props => {
9095
</Grid>
9196
);
9297
};
98+

apps/frontend/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ import {AvatarEditorGridPartItem, CategoryData, IAvatarEditorCategoryModel} from
44
import {AutoGrid} from "../../../../common";
55
import {AvatarEditorFigureSetItemView} from "./AvatarEditorFigureSetItemView";
66

7+
const TSHIRT_FOOTBALL_GATE = [3111, 3110, 3109, 3030, 3114, 266, 265, 262, 3113, 3112, 691, 690, 667];
8+
const NUMBER_BEHIND_FOOTBALL_GATE = [3128, 3127, 3126, 3125, 3124, 3123, 3122, 3121, 3120, 3119];
9+
const PANTS_FOOTBALL_GATE = [3116, 281, 275, 715, 700, 696, 3006];
10+
const SHOES_FOOTBALL_GATE = [3115, 3068, 906];
11+
712
export interface AvatarEditorFigureSetViewProps {
813
model: IAvatarEditorCategoryModel;
914
category: CategoryData;
15+
isFromFootballGate: boolean;
1016
setMaxPaletteCount: Dispatch<SetStateAction<number>>;
1117
}
1218

1319
export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = props => {
14-
const {model = null, category = null, setMaxPaletteCount = null} = props;
20+
const {model = null, category = null, isFromFootballGate = false, setMaxPaletteCount = null} = props;
1521
const elementRef = useRef<HTMLDivElement>(null);
1622

1723
const selectPart = useCallback(
@@ -38,7 +44,15 @@ export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = pro
3844
return (
3945
<AutoGrid innerRef={elementRef} columnCount={3} columnMinHeight={50}>
4046
{category.parts.length > 0 &&
41-
category.parts.map((item, index) => <AvatarEditorFigureSetItemView key={index} partItem={item} onClick={event => selectPart(item)} />)}
47+
category.parts.map(
48+
item =>
49+
(!isFromFootballGate ||
50+
(isFromFootballGate && TSHIRT_FOOTBALL_GATE.includes(item.id)) ||
51+
NUMBER_BEHIND_FOOTBALL_GATE.includes(item.id) ||
52+
PANTS_FOOTBALL_GATE.includes(item.id) ||
53+
SHOES_FOOTBALL_GATE.includes(item.id)) && <AvatarEditorFigureSetItemView key={item.id} partItem={item} onClick={event => selectPart(item)} />
54+
)}
4255
</AutoGrid>
4356
);
4457
};
58+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {FC} from "react";
2+
3+
import {CreateLinkEvent, FigureData, LocalizeText} from "../../../../api";
4+
import {Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView} from "../../../../common";
5+
import {useFurnitureFootballGateWidget} from "../../../../hooks";
6+
7+
export const FurnitureFootballGateView: FC<{}> = props => {
8+
const {objectId, setObjectId, onClose} = useFurnitureFootballGateWidget();
9+
10+
const onGender = (gender: string) => {
11+
CreateLinkEvent(`avatar-editor/show/${gender}/${objectId}`);
12+
setObjectId(-1);
13+
};
14+
15+
if (objectId === -1) return null;
16+
17+
return (
18+
<NitroCardView className="nitro-football-gate no-resize" theme="primary-slim">
19+
<NitroCardHeaderView headerText={LocalizeText("widget.furni.clothingchange.gender.title")} onCloseClick={onClose} />
20+
<NitroCardContentView className="football-gate-content">
21+
<Flex fullWidth center>
22+
<Column>{LocalizeText("widget.furni.clothingchange.gender.info")}</Column>
23+
</Flex>
24+
<Flex className="mt-4 px-2" justifyContent="between">
25+
<Button className="size-buttons" onClick={e => onGender(FigureData.MALE)}>
26+
{LocalizeText("widget.furni.clothingchange.gender.male")}
27+
</Button>
28+
<Button className="size-buttons" onClick={e => onGender(FigureData.FEMALE)}>
29+
{LocalizeText("widget.furni.clothingchange.gender.female")}
30+
</Button>
31+
</Flex>
32+
</NitroCardContentView>
33+
</NitroCardView>
34+
);
35+
};

apps/frontend/src/components/room/widgets/furniture/FurnitureWidgets.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,15 @@
514514
}
515515
}
516516
}
517+
518+
.nitro-football-gate {
519+
width: 300px;
520+
521+
.football-gate-content {
522+
color: black;
523+
524+
.size-buttons {
525+
width: 100px;
526+
}
527+
}
528+
}

apps/frontend/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {FurnitureCraftingView} from "./FurnitureCraftingView";
77
import {FurnitureDimmerView} from "./FurnitureDimmerView";
88
import {FurnitureExchangeCreditView} from "./FurnitureExchangeCreditView";
99
import {FurnitureExternalImageView} from "./FurnitureExternalImageView";
10+
import {FurnitureFootballGateView} from "./FurnitureFootballGateView";
1011
import {FurnitureFriendFurniView} from "./FurnitureFriendFurniView";
1112
import {FurnitureGiftOpeningView} from "./FurnitureGiftOpeningView";
1213
import {FurnitureHighScoreView} from "./FurnitureHighScoreView";
@@ -43,6 +44,8 @@ export const FurnitureWidgetsView: FC<{}> = props => {
4344
<FurnitureTrophyView />
4445
<FurnitureContextMenuView />
4546
<FurnitureYoutubeDisplayView />
47+
<FurnitureFootballGateView />
4648
</Base>
4749
);
4850
};
51+

apps/frontend/src/hooks/rooms/widgets/furniture/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from "./useFurnitureCraftingWidget";
55
export * from "./useFurnitureDimmerWidget";
66
export * from "./useFurnitureExchangeWidget";
77
export * from "./useFurnitureExternalImageWidget";
8+
export * from './useFurnitureFootballGateWidget';
89
export * from "./useFurnitureFriendFurniWidget";
910
export * from "./useFurnitureHighScoreWidget";
1011
export * from "./useFurnitureInternalLinkWidget";

0 commit comments

Comments
 (0)