mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-23 06:40:50 +01:00
Feature - Football Gate
This commit is contained in:
parent
aba4ddf2db
commit
ec284d5b52
@ -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';
|
||||
@ -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 =>
|
||||
{
|
||||
@ -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();
|
||||
@ -72,13 +83,21 @@ export const AvatarEditorView: FC<{}> = props =>
|
||||
{
|
||||
const categories = new Map();
|
||||
|
||||
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(() =>
|
||||
{
|
||||
@ -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) =>
|
||||
{
|
||||
@ -155,6 +174,9 @@ export const AvatarEditorView: FC<{}> = props =>
|
||||
{
|
||||
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])
|
||||
@ -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(() =>
|
||||
{
|
||||
@ -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(() =>
|
||||
{
|
||||
@ -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 =>
|
||||
{
|
||||
@ -278,21 +310,24 @@ export const AvatarEditorView: FC<{}> = props =>
|
||||
</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 }>
|
||||
{ (!genderFootballGate) &&
|
||||
<ButtonGroup>
|
||||
<Button variant="secondary" onClick={ event => processAction(AvatarEditorAction.ACTION_RESET) }>
|
||||
<FaUndo className="fa-icon" />
|
||||
@ -304,6 +339,7 @@ export const AvatarEditorView: FC<{}> = props =>
|
||||
<FaDice className="fa-icon" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
}
|
||||
<Button className="w-100" variant="success" onClick={ event => processAction(AvatarEditorAction.ACTION_SAVE) }>
|
||||
{ LocalizeText('avatareditor.save') }
|
||||
</Button>
|
||||
|
@ -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);
|
||||
|
||||
@ -68,14 +71,21 @@ 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) }>
|
||||
<div key={ name }>
|
||||
<Flex center pointer className="category-item" onClick={ event => selectCategory(name) }>
|
||||
{ (isFromFootballGate && CATEGORY_FOOTBALL_GATE.includes(category.name)) &&
|
||||
<AvatarEditorIcon icon={ category.name } selected={ (activeCategory === category) } />
|
||||
}
|
||||
{ (!isFromFootballGate) &&
|
||||
<AvatarEditorIcon icon={ category.name } selected={ (activeCategory === category) } />
|
||||
}
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
}) }
|
||||
</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) &&
|
||||
|
@ -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) =>
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -524,3 +524,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-football-gate
|
||||
{
|
||||
width: 300px;
|
||||
|
||||
.football-gate-content
|
||||
{
|
||||
color: black;
|
||||
|
||||
.size-buttons
|
||||
{
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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';
|
||||
@ -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 =>
|
||||
@ -43,6 +44,7 @@ export const FurnitureWidgetsView: FC<{}> = props =>
|
||||
<FurnitureTrophyView />
|
||||
<FurnitureContextMenuView />
|
||||
<FurnitureYoutubeDisplayView />
|
||||
<FurnitureFootballGateView />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -0,0 +1,38 @@
|
||||
import { RoomEngineTriggerWidgetEvent } from '@nitrots/nitro-renderer';
|
||||
import { useState } from 'react';
|
||||
import { GetRoomEngine, IsOwnerOfFurniture } from '../../../../api';
|
||||
import { useRoomEngineEvent } from '../../../events';
|
||||
import { useFurniRemovedEvent } from '../../engine';
|
||||
|
||||
const useFurnitureFootballGateWidgetState = () =>
|
||||
{
|
||||
const [ objectId, setObjectId ] = useState<number>(-1);
|
||||
const [ category, setCategory ] = useState<number>(-1);
|
||||
|
||||
const onClose = () =>
|
||||
{
|
||||
setObjectId(-1);
|
||||
setCategory(-1);
|
||||
}
|
||||
|
||||
useRoomEngineEvent<RoomEngineTriggerWidgetEvent>(RoomEngineTriggerWidgetEvent.REQUEST_CLOTHING_CHANGE, event =>
|
||||
{
|
||||
const roomObject = GetRoomEngine().getRoomObject(event.roomId, event.objectId, event.category);
|
||||
|
||||
if(!roomObject || !IsOwnerOfFurniture(roomObject)) return;
|
||||
|
||||
setObjectId(event.objectId);
|
||||
setCategory(event.category);
|
||||
});
|
||||
|
||||
useFurniRemovedEvent(((objectId !== -1) && (category !== -1)), event =>
|
||||
{
|
||||
if((event.id !== objectId) || (event.category !== category)) return;
|
||||
|
||||
onClose();
|
||||
});
|
||||
|
||||
return { objectId, setObjectId, onClose };
|
||||
}
|
||||
|
||||
export const useFurnitureFootballGateWidget = useFurnitureFootballGateWidgetState;
|
Loading…
Reference in New Issue
Block a user