Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 68 additions & 32 deletions src/components/avatar-editor/AvatarEditorView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AvatarEditorFigureCategory, FigureSetIdsMessageEvent, GetWardrobeMessageComposer, IAvatarFigureContainer, ILinkEventTracker, UserFigureComposer, UserWardrobePageEvent } from '@nitrots/nitro-renderer';
import { AvatarEditorFigureCategory, FigureSetIdsMessageEvent, GetWardrobeMessageComposer, IAvatarFigureContainer, ILinkEventTracker, SetClothingChangeDataMessageComposer, UserFigureComposer, UserWardrobePageEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { FaDice, FaTrash, FaUndo } from 'react-icons/fa';
import { AddEventLinkTracker, AvatarEditorAction, AvatarEditorUtilities, BodyModel, FigureData, generateRandomFigure, GetAvatarRenderManager, GetClubMemberLevel, GetConfiguration, GetSessionDataManager, HeadModel, IAvatarEditorCategoryModel, LegModel, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TorsoModel } from '../../api';
import { AddEventLinkTracker, AvatarEditorAction, AvatarEditorUtilities, BodyModel, FigureData, GetAvatarRenderManager, GetClubMemberLevel, GetConfiguration, GetSessionDataManager, HeadModel, IAvatarEditorCategoryModel, LegModel, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TorsoModel, generateRandomFigure } from '../../api';
import { Button, ButtonGroup, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { useMessageEvent } from '../../hooks';
import { AvatarEditorFigurePreviewView } from './views/AvatarEditorFigurePreviewView';
Expand All @@ -10,6 +10,8 @@ import { AvatarEditorWardrobeView } from './views/AvatarEditorWardrobeView';

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

export const AvatarEditorView: FC<{}> = props =>
{
Expand All @@ -26,9 +28,18 @@ export const AvatarEditorView: FC<{}> = props =>
const [ lastGender, setLastGender ] = useState<string>(null);
const [ needsReset, setNeedsReset ] = useState(true);
const [ isInitalized, setIsInitalized ] = useState(false);

const [ genderFootballGate, setGenderFootballGate ] = useState<string>(null);
const [ objectFootballGate, setObjectFootballGate ] = useState<number>(null);

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

const onClose = () =>
{
setGenderFootballGate(null);
setObjectFootballGate(null);
setIsVisible(false);
}

useMessageEvent<FigureSetIdsMessageEvent>(FigureSetIdsMessageEvent, event =>
{
const parser = event.getParser();
Expand Down Expand Up @@ -72,13 +83,21 @@ export const AvatarEditorView: FC<{}> = props =>
{
const categories = new Map();

categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel());
categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel());
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
if (!genderFootballGate)
{
categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel());
categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel());
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
}
else
{
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
}

setCategories(categories);
}, []);
}, [ genderFootballGate ]);

const setupFigures = useCallback(() =>
{
Expand Down Expand Up @@ -135,11 +154,11 @@ export const AvatarEditorView: FC<{}> = props =>
resetCategories();
return;
case AvatarEditorAction.ACTION_SAVE:
SendMessageComposer(new UserFigureComposer(figureData.gender, figureData.getFigureString()));
setIsVisible(false);
!genderFootballGate ? SendMessageComposer(new UserFigureComposer(figureData.gender, figureData.getFigureString())) : SendMessageComposer(new SetClothingChangeDataMessageComposer(objectFootballGate, genderFootballGate, figureData.getFigureString()));
onClose();
return;
}
}, [ figureData, lastFigure, lastGender, figureSetIds, loadAvatarInEditor, resetCategories ])
}, [ loadAvatarInEditor, figureData, resetCategories, lastFigure, lastGender, figureSetIds, genderFootballGate, objectFootballGate ])

const setGender = useCallback((gender: string) =>
{
Expand All @@ -154,7 +173,10 @@ export const AvatarEditorView: FC<{}> = props =>
linkReceived: (url: string) =>
{
const parts = url.split('/');


setGenderFootballGate(parts[2] ? parts[2] : null);
setObjectFootballGate(parts[3] ? Number(parts[3]) : null);

if(parts.length < 2) return;

switch(parts[1])
Expand Down Expand Up @@ -202,8 +224,8 @@ export const AvatarEditorView: FC<{}> = props =>
{
if(!categories) return;

selectCategory(AvatarEditorFigureCategory.GENERIC);
}, [ categories, selectCategory ]);
selectCategory(!genderFootballGate ? AvatarEditorFigureCategory.GENERIC : AvatarEditorFigureCategory.TORSO);
}, [ categories, genderFootballGate, selectCategory ]);

useEffect(() =>
{
Expand Down Expand Up @@ -248,9 +270,19 @@ export const AvatarEditorView: FC<{}> = props =>
{
if(!isVisible || !isInitalized || !needsReset) return;

loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender);
loadAvatarInEditor(!genderFootballGate ? GetSessionDataManager().figure : (genderFootballGate === FigureData.MALE ? DEFAULT_MALE_FOOTBALL_GATE : DEFAULT_FEMALE_FOOTBALL_GATE), !genderFootballGate ? GetSessionDataManager().gender : genderFootballGate);
setNeedsReset(false);
}, [ isVisible, isInitalized, needsReset, loadAvatarInEditor ]);
}, [ isVisible, isInitalized, needsReset, loadAvatarInEditor, genderFootballGate ]);

useEffect(() => // This is so when you have the look editor open and you change the mode to Boy or Girl
{
if(!isVisible) return;

return () =>
{
setNeedsReset(true);
}
}, [ isVisible, genderFootballGate ]);

useEffect(() =>
{
Expand All @@ -266,7 +298,7 @@ export const AvatarEditorView: FC<{}> = props =>

return (
<NitroCardView uniqueKey="avatar-editor" className="nitro-avatar-editor">
<NitroCardHeaderView headerText={ LocalizeText('avatareditor.title') } onCloseClick={ event => setIsVisible(false) } />
<NitroCardHeaderView headerText={ !genderFootballGate ? LocalizeText('avatareditor.title') : LocalizeText('widget.furni.clothingchange.editor.title') } onCloseClick={ onClose } />
<NitroCardTabsView>
{ categories && (categories.size > 0) && Array.from(categories.keys()).map(category =>
{
Expand All @@ -278,32 +310,36 @@ export const AvatarEditorView: FC<{}> = props =>
</NitroCardTabsItemView>
);
}) }
<NitroCardTabsItemView isActive={ isWardrobeVisible } onClick={ event => setIsWardrobeVisible(true) }>
{ LocalizeText('avatareditor.category.wardrobe') }
</NitroCardTabsItemView>
{ (!genderFootballGate) &&
<NitroCardTabsItemView isActive={ isWardrobeVisible } onClick={ event => setIsWardrobeVisible(true) }>
{ LocalizeText('avatareditor.category.wardrobe') }
</NitroCardTabsItemView>
}
</NitroCardTabsView>
<NitroCardContentView>
<Grid>
<Column size={ 9 } overflow="hidden">
{ (activeCategory && !isWardrobeVisible) &&
<AvatarEditorModelView model={ activeCategory } gender={ figureData.gender } setGender={ setGender } /> }
<AvatarEditorModelView model={ activeCategory } gender={ figureData.gender } isFromFootballGate={ !genderFootballGate ? false : true } setGender={ setGender } /> }
{ isWardrobeVisible &&
<AvatarEditorWardrobeView figureData={ figureData } savedFigures={ savedFigures } setSavedFigures={ setSavedFigures } loadAvatarInEditor={ loadAvatarInEditor } /> }
</Column>
<Column size={ 3 } overflow="hidden">
<AvatarEditorFigurePreviewView figureData={ figureData } />
<Column grow gap={ 1 }>
<ButtonGroup>
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_RESET) }>
<FaUndo className="fa-icon" />
</Button>
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_CLEAR) }>
<FaTrash className="fa-icon" />
</Button>
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_RANDOMIZE) }>
<FaDice className="fa-icon" />
</Button>
</ButtonGroup>
{ (!genderFootballGate) &&
<ButtonGroup>
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_RESET) }>
<FaUndo className="fa-icon" />
</Button>
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_CLEAR) }>
<FaTrash className="fa-icon" />
</Button>
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_RANDOMIZE) }>
<FaDice className="fa-icon" />
</Button>
</ButtonGroup>
}
<Button className="w-100" variant="success" onClick={ event => processAction(AvatarEditorAction.ACTION_SAVE) }>
{ LocalizeText('avatareditor.save') }
</Button>
Expand Down
12 changes: 8 additions & 4 deletions src/components/avatar-editor/views/AvatarEditorModelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ import { Column, Flex, Grid } from '../../../common';
import { AvatarEditorIcon } from './AvatarEditorIcon';
import { AvatarEditorFigureSetView } from './figure-set/AvatarEditorFigureSetView';
import { AvatarEditorPaletteSetView } from './palette-set/AvatarEditorPaletteSetView';

const CATEGORY_FOOTBALL_GATE = [ 'ch', 'cp', 'lg', 'sh' ];
export interface AvatarEditorModelViewProps
{
model: IAvatarEditorCategoryModel;
gender: string;
isFromFootballGate: boolean;
setGender: Dispatch<SetStateAction<string>>;
}

export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
{
const { model = null, gender = null, setGender = null } = props;
const { model = null, gender = null, isFromFootballGate = false, setGender = null } = props;
const [ activeCategory, setActiveCategory ] = useState<CategoryData>(null);
const [ maxPaletteCount, setMaxPaletteCount ] = useState(1);

Expand Down Expand Up @@ -68,14 +71,15 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
const category = model.categories.get(name);

return (
<Flex center pointer key={ name } className="category-item" onClick={ event => selectCategory(name) }>
(!isFromFootballGate || (isFromFootballGate && CATEGORY_FOOTBALL_GATE.includes(category.name))) &&
<Flex key={ category.name } center pointer className="category-item" onClick={ event => selectCategory(name) }>
<AvatarEditorIcon icon={ category.name } selected={ (activeCategory === category) } />
</Flex>
);
)
}) }
</Column>
<Column size={ 5 } overflow="hidden">
<AvatarEditorFigureSetView model={ model } category={ activeCategory } setMaxPaletteCount={ setMaxPaletteCount } />
<AvatarEditorFigureSetView model={ model } category={ activeCategory } isFromFootballGate={ isFromFootballGate } setMaxPaletteCount={ setMaxPaletteCount } />
</Column>
<Column size={ 5 } overflow="hidden">
{ (maxPaletteCount >= 1) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import { AvatarEditorGridPartItem, CategoryData, IAvatarEditorCategoryModel } fr
import { AutoGrid } from '../../../../common';
import { AvatarEditorFigureSetItemView } from './AvatarEditorFigureSetItemView';

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

export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = props =>
{
const { model = null, category = null, setMaxPaletteCount = null } = props;
const { model = null, category = null, isFromFootballGate = false, setMaxPaletteCount = null } = props;
const elementRef = useRef<HTMLDivElement>(null);

const selectPart = useCallback((item: AvatarEditorGridPartItem) =>
Expand All @@ -37,8 +42,10 @@ export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = pro

return (
<AutoGrid innerRef={ elementRef } columnCount={ 3 } columnMinHeight={ 50 }>
{ (category.parts.length > 0) && category.parts.map((item, index) =>
<AvatarEditorFigureSetItemView key={ index } partItem={ item } onClick={ event => selectPart(item) } />) }
{ (category.parts.length > 0) && category.parts.map(item =>
(!isFromFootballGate || (isFromFootballGate && TSHIRT_FOOTBALL_GATE.includes(item.id) || NUMBER_BEHIND_FOOTBALL_GATE.includes(item.id) || PANTS_FOOTBALL_GATE.includes(item.id) || SHOES_FOOTBALL_GATE.includes(item.id))) &&
<AvatarEditorFigureSetItemView key={ item.id } partItem={ item } onClick={ event => selectPart(item) } />)
}
</AutoGrid>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { FC } from 'react';
import { CreateLinkEvent, FigureData, LocalizeText } from '../../../../api';
import { Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useFurnitureFootballGateWidget } from '../../../../hooks';

export const FurnitureFootballGateView: FC<{}> = props =>
{
const { objectId, setObjectId, onClose } = useFurnitureFootballGateWidget();

const onGender = (gender: string) =>
{
CreateLinkEvent(`avatar-editor/show/${ gender }/${ objectId }`);
setObjectId(-1);
}

if(objectId === -1) return null;

return (
<NitroCardView className="nitro-football-gate no-resize" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('widget.furni.clothingchange.gender.title') } onCloseClick={ onClose } />
<NitroCardContentView className="football-gate-content">
<Flex fullWidth center>
<Column>{ LocalizeText('widget.furni.clothingchange.gender.info') }</Column>
</Flex>
<Flex className="mt-4 px-2" justifyContent="between">
<Button className="size-buttons" onClick={ (e) => onGender(FigureData.MALE) }>
{ LocalizeText('widget.furni.clothingchange.gender.male') }
</Button>
<Button className="size-buttons" onClick={ (e) => onGender(FigureData.FEMALE) }>
{ LocalizeText('widget.furni.clothingchange.gender.female') }
</Button>
</Flex>
</NitroCardContentView>
</NitroCardView>
);
}
15 changes: 15 additions & 0 deletions src/components/room/widgets/furniture/FurnitureWidgets.scss
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,18 @@
}
}
}

.nitro-football-gate
{
width: 300px;

.football-gate-content
{
color: black;

.size-buttons
{
width: 100px;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { FC } from 'react';
import { Base } from '../../../../common';
import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView';
import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView';
import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView';
import { FurnitureCraftingView } from './FurnitureCraftingView';
import { FurnitureDimmerView } from './FurnitureDimmerView';
import { FurnitureExchangeCreditView } from './FurnitureExchangeCreditView';
import { FurnitureExternalImageView } from './FurnitureExternalImageView';
import { FurnitureFootballGateView } from './FurnitureFootballGateView';
import { FurnitureFriendFurniView } from './FurnitureFriendFurniView';
import { FurnitureGiftOpeningView } from './FurnitureGiftOpeningView';
import { FurnitureHighScoreView } from './FurnitureHighScoreView';
Expand All @@ -18,6 +18,7 @@ import { FurnitureStackHeightView } from './FurnitureStackHeightView';
import { FurnitureStickieView } from './FurnitureStickieView';
import { FurnitureTrophyView } from './FurnitureTrophyView';
import { FurnitureYoutubeDisplayView } from './FurnitureYoutubeDisplayView';
import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView';
import { FurniturePlaylistEditorWidgetView } from './playlist-editor/FurniturePlaylistEditorWidgetView';

export const FurnitureWidgetsView: FC<{}> = props =>
Expand All @@ -43,6 +44,7 @@ export const FurnitureWidgetsView: FC<{}> = props =>
<FurnitureTrophyView />
<FurnitureContextMenuView />
<FurnitureYoutubeDisplayView />
<FurnitureFootballGateView />
</Base>
);
}
1 change: 1 addition & 0 deletions src/hooks/rooms/widgets/furniture/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './useFurnitureCraftingWidget';
export * from './useFurnitureDimmerWidget';
export * from './useFurnitureExchangeWidget';
export * from './useFurnitureExternalImageWidget';
export * from './useFurnitureFootballGateWidget';
export * from './useFurnitureFriendFurniWidget';
export * from './useFurnitureHighScoreWidget';
export * from './useFurnitureInternalLinkWidget';
Expand Down
Loading