diff --git a/src/assets/images/wired/card-action-corners.png b/src/assets/images/wired/card-action-corners.png new file mode 100644 index 00000000..faec2349 Binary files /dev/null and b/src/assets/images/wired/card-action-corners.png differ diff --git a/src/views/wired/WiredView.scss b/src/views/wired/WiredView.scss index bab60efb..ce1bc799 100644 --- a/src/views/wired/WiredView.scss +++ b/src/views/wired/WiredView.scss @@ -1,5 +1,6 @@ .nitro-wired { width: 300px; + padding:7px; .icon { width: 16px; @@ -35,4 +36,125 @@ background-image: url('../../assets/images/wired/icon_wired_rotate_counter_clockwise.png'); } } + + .nitro-wired-header { + color: #000; + margin-bottom:3px; + + .nitro-wired-title, .nitro-wired-close { + border:1px solid rgba($black,.8); + background-image: linear-gradient(45deg, #00d9cb 25%, #00bdb0 25%, #00bdb0 50%, #00d9cb 50%, #00d9cb 75%, #00bdb0 75%, #00bdb0 100%); + background-size: 197.99px 197.99px; + animation: wiredSlider 3s linear infinite; + text-align: center; + box-shadow:inset 0 0 0 2px rgba($white,.6), 0 2px rgba($black,.4); + } + + .nitro-wired-title { + margin-right:3px; + } + + .nitro-wired-close { + min-width: 23px; + } + } + + &.nitro-wired-trigger { + background-color: #3b2516 !important; + border: 1px solid #000 !important; + box-shadow: inset 0px -2px #50321f, + inset 0px -3px #86583b, + inset 0 0 0 1px #86583b, + inset 0 0 0 3px #644029, + inset 0 0 0 4px rgba($black,.4) !important; + + .bg-light,.bg-primary { + background-color: transparent !important; + } + + .bg-dark { + background-color: #000 !important; + } + } + + &.nitro-wired-action { + background-color: #686868 !important; + border: 1px solid #000 !important; + box-shadow: inset 0px -2px #9d9d9d, + inset 0px -3px #c5c5c5, + inset 0 0 0 1px #c5c5c5, + inset 0 0 0 3px #9d9d9d, + inset 0 0 0 4px rgba($black,.4) !important; + + .bg-light,.bg-primary { + background-color: transparent !important; + } + + .bg-dark { + background-color: #000 !important; + } + + &::before, + &::after, + .content-area::before, + .content-area::after { + content: ''; + height: 6px; + width: 6px; + position: absolute; + background-image: url('../../assets/images/wired/card-action-corners.png'); + } + + &::before { + background-position: 0 0; + top: 0; + left: 0; + } + + &::after { + background-position: 6px 0; + top: 0; + right: 0; + } + + .content-area { + &::before { + background-position: 0 6px; + bottom: 0; + left: 0; + } + + &::after { + background-position: 6px 6px; + bottom: 0; + right: 0; + } + } + } + + &.nitro-wired-condition { + background-color: #cfd2dd !important; + border: 1px solid #000 !important; + box-shadow: inset 0 0 0 3px #efefef, inset 4px 4px #abaeb9 !important; + color: #000; + + .bg-light,.bg-primary { + background-color: transparent !important; + } + + .bg-dark { + background-color: #000 !important; + } + } +} + + +@keyframes wiredSlider { + 0% { + background-position: 0 0; + } + + 100% { + background-position: 0 -197.99px; + } } diff --git a/src/views/wired/common/GetWiredActionLayout.tsx b/src/views/wired/common/GetWiredActionLayout.tsx index 912288c2..fab75242 100644 --- a/src/views/wired/common/GetWiredActionLayout.tsx +++ b/src/views/wired/common/GetWiredActionLayout.tsx @@ -9,6 +9,7 @@ import { WiredActionCallAnotherStackView } from '../views/actions/call-another-s import { WiredActionChaseView } from '../views/actions/chase/WiredActionChaseView'; import { WiredActionChatView } from '../views/actions/chat/WiredActionChatView'; import { WiredActionFleeView } from '../views/actions/flee/WiredActionFleeView'; +import { WiredActionGiveRewardView } from '../views/actions/give-reward/WiredActionGiveRewardView'; import { WiredActionGiveScoreToPredefinedTeamView } from '../views/actions/give-score-to-predefined-team/WiredActionGiveScoreToPredefinedTeamView'; import { WiredActionGiveScoreView } from '../views/actions/give-score/WiredActionGiveScoreView'; import { WiredActionJoinTeamView } from '../views/actions/join-team/WiredActionJoinTeamView'; @@ -50,6 +51,8 @@ export function GetWiredActionLayout(code: number): JSX.Element return ; case WiredActionLayout.FLEE: return ; + case WiredActionLayout.GIVE_REWARD: + return ; case WiredActionLayout.GIVE_SCORE: return ; case WiredActionLayout.GIVE_SCORE_TO_PREDEFINED_TEAM: diff --git a/src/views/wired/common/GetWiredConditionLayout.tsx b/src/views/wired/common/GetWiredConditionLayout.tsx index 4e5d38bb..e56caebe 100644 --- a/src/views/wired/common/GetWiredConditionLayout.tsx +++ b/src/views/wired/common/GetWiredConditionLayout.tsx @@ -4,6 +4,7 @@ import { WiredConditionActorIsOnFurniView } from '../views/conditions/actor-is-o import { WiredConditionActorIsTeamMemberView } from '../views/conditions/actor-is-team-member/WiredConditionActorIsTeamMemberView'; import { WiredConditionActorIsWearingBadgeView } from '../views/conditions/actor-is-wearing-badge/WiredConditionActorIsWearingBadgeView'; import { WiredConditionActorIsWearingEffectView } from '../views/conditions/actor-is-wearing-effect/WiredConditionActorIsWearingEffectView'; +import { WiredConditionDateRangeView } from '../views/conditions/date-range/WiredConditionDateRangeView'; import { WiredConditionFurniHasAvatarOnView } from '../views/conditions/furni-has-avatar-on/WiredConditionFurniHasAvatarOnView'; import { WiredConditionFurniHasFurniOnView } from '../views/conditions/furni-has-furni-on/WiredConditionFurniHasFurniOnView'; import { WiredConditionFurniHasNotFurniOnView } from '../views/conditions/furni-has-not-furni-on/WiredConditionFurniHasNotFurniOnView'; @@ -35,6 +36,8 @@ export function GetWiredConditionLayout(code: number): JSX.Element case WiredConditionlayout.ACTOR_IS_WEARING_EFFECT: case WiredConditionlayout.NOT_ACTOR_WEARING_EFFECT: return ; + case WiredConditionlayout.DATE_RANGE_ACTIVE: + return ; case WiredConditionlayout.FURNIS_HAVE_AVATARS: case WiredConditionlayout.FURNI_NOT_HAVE_HABBO: return ; diff --git a/src/views/wired/views/actions/give-reward/WiredActionGiveRewardView.tsx b/src/views/wired/views/actions/give-reward/WiredActionGiveRewardView.tsx new file mode 100644 index 00000000..0d857a67 --- /dev/null +++ b/src/views/wired/views/actions/give-reward/WiredActionGiveRewardView.tsx @@ -0,0 +1,173 @@ +import Slider from 'rc-slider/lib/Slider'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { LocalizeText } from '../../../../../utils/LocalizeText'; +import { useWiredContext } from '../../../context/WiredContext'; +import { WiredFurniType } from '../../../WiredView.types'; +import { WiredActionBaseView } from '../base/WiredActionBaseView'; + +export const WiredActionGiveRewardView: FC<{}> = props => +{ + const [ limitEnabled, setLimitEnabled ] = useState(false); + const [ rewardTime, setRewardTime ] = useState(1); + const [ uniqueRewards, setUniqueRewards ] = useState(false); + const [ rewardsLimit, setRewardsLimit ] = useState(1); + const [ limitationInterval, setLimitationInterval ] = useState(1); + const [ rewards, setRewards ] = useState<{ isBadge: boolean, itemCode: string, probability: number }[]>([]); + + const { trigger = null, setIntParams = null, setStringParam = null } = useWiredContext(); + + useEffect(() => + { + setRewardTime(trigger.intData.length > 0 ? trigger.intData[0] : 0); + setUniqueRewards(trigger.intData.length > 1 ? trigger.intData[1] === 1 : false); + setRewardsLimit(trigger.intData.length > 2 ? trigger.intData[2] : 0); + setLimitationInterval(trigger.intData.length > 3 ? trigger.intData[3] : 0); + setLimitEnabled(trigger.intData.length > 3 ? trigger.intData[3] > 0 : false); + + const readRewards: { isBadge: boolean, itemCode: string, probability: number }[] = []; + + if(trigger.stringData.length > 0 && trigger.stringData.includes(';')) + { + const splittedRewards = trigger.stringData.split(';'); + + for(const rawReward of splittedRewards) + { + const reward = rawReward.split(','); + + if(reward.length !== 3) continue; + + readRewards.push({ isBadge: reward[0] === '0', itemCode: reward[1], probability: Number(reward[2]) }); + } + } + + if(readRewards.length === 0) + { + readRewards.push({ isBadge: false, itemCode: '', probability: null }); + } + + setRewards(readRewards); + }, [ trigger ]); + + const addReward = useCallback(() => + { + setRewards(rewards => [...rewards, { isBadge: false, itemCode: '', probability: null }]); + }, [ setRewards ]); + + const removeReward = useCallback((index: number) => + { + const rewardsClone = Array.from(rewards); + rewardsClone.splice(index, 1); + + setRewards(rewardsClone); + }, [ rewards, setRewards ]); + + const updateReward = useCallback((index: number, isBadge: boolean, itemCode: string, probability: number) => + { + const rewardsClone = Array.from(rewards); + const reward = rewardsClone[index]; + + if(!reward) return; + + reward.isBadge = isBadge; + reward.itemCode = itemCode; + reward.probability = probability; + + setRewards(rewardsClone); + }, [ rewards, setRewards ]); + + const save = useCallback(() => + { + let stringRewards = []; + + for(const reward of rewards) + { + if(!reward.itemCode) continue; + + const rewardsString = [reward.isBadge ? '0' : '1', reward.itemCode, reward.probability.toString()]; + stringRewards.push(rewardsString.join(',')); + } + + if(stringRewards.length > 0) + { + setStringParam(stringRewards.join(';')); + setIntParams([rewardTime, uniqueRewards ? 1 : 0, rewardsLimit, limitationInterval]); + } + }, [ rewardTime, uniqueRewards, rewardsLimit, limitationInterval, rewards, setIntParams, setStringParam ]); + + return ( + +
+ setLimitEnabled(e.target.checked)} /> + +
+ { !limitEnabled &&
+ Reward limit not set. Make sure rewards are badges or non-tradeable items. +
} + { limitEnabled && setRewardsLimit(event) } + /> } +
+
How ofter can a user be rewarded?
+
+ + { rewardTime > 0 && setLimitationInterval(Number(event.target.value)) } /> } +
+
+
+ setUniqueRewards(e.target.checked)} /> + +
+
If checked each reward will be given once to each user. This will disable the probabilities option.
+
+
+
Rewards
+
+
+ + + + + + + + + + + { rewards && rewards.map((reward, index) => + { + return ( + + + + + + + ) + }) } + +
Badge?Item CodeProbability
+ updateReward(index, e.target.checked, reward.itemCode, reward.probability)} /> + + updateReward(index, reward.isBadge, e.target.value, reward.probability) } /> + + updateReward(index, reward.isBadge, reward.itemCode, Number(e.target.value)) } /> + + { index > 0 && } +
+
+ ); +} diff --git a/src/views/wired/views/actions/move-and-rotate-furni/WiredActionMoveAndRotateFurniView.tsx b/src/views/wired/views/actions/move-and-rotate-furni/WiredActionMoveAndRotateFurniView.tsx index f6b0ef97..5995dd4d 100644 --- a/src/views/wired/views/actions/move-and-rotate-furni/WiredActionMoveAndRotateFurniView.tsx +++ b/src/views/wired/views/actions/move-and-rotate-furni/WiredActionMoveAndRotateFurniView.tsx @@ -54,7 +54,7 @@ export const WiredActionMoveAndRotateFurniView: FC<{}> = props =>
-
+
{ directionOptions.map(option => { return ( diff --git a/src/views/wired/views/base/WiredBaseView.tsx b/src/views/wired/views/base/WiredBaseView.tsx index 9e947e62..105218a3 100644 --- a/src/views/wired/views/base/WiredBaseView.tsx +++ b/src/views/wired/views/base/WiredBaseView.tsx @@ -2,7 +2,7 @@ import { FC, useCallback, useEffect, useState } from 'react'; import { GetSessionDataManager } from '../../../../api'; import { WiredEvent } from '../../../../events'; import { dispatchUiEvent } from '../../../../hooks/events'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { NitroCardContentView, NitroCardView } from '../../../../layout'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { useWiredContext } from '../../context/WiredContext'; import { WiredFurniType } from '../../WiredView.types'; @@ -52,9 +52,12 @@ export const WiredBaseView: FC = props => }, [ setTrigger ]); return ( - - - + +
+
{LocalizeText('wiredfurni.title')}
+
+
+
{ wiredName }
@@ -73,8 +76,8 @@ export const WiredBaseView: FC = props =>
{ LocalizeText('wiredfurni.pickfurnis.desc') }
}
- - + +
diff --git a/src/views/wired/views/conditions/date-range/WiredConditionDateRangeView.tsx b/src/views/wired/views/conditions/date-range/WiredConditionDateRangeView.tsx new file mode 100644 index 00000000..a0d3c0dd --- /dev/null +++ b/src/views/wired/views/conditions/date-range/WiredConditionDateRangeView.tsx @@ -0,0 +1,62 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { LocalizeText } from '../../../../../utils/LocalizeText'; +import { useWiredContext } from '../../../context/WiredContext'; +import { WiredFurniType } from '../../../WiredView.types'; +import { WiredConditionBaseView } from '../base/WiredConditionBaseView'; + +export const WiredConditionDateRangeView: FC<{}> = props => +{ + const [ startDate, setStartDate ] = useState(''); + const [ endDate, setEndDate ] = useState(''); + const { trigger = null, setIntParams = null } = useWiredContext(); + + const dateToString = useCallback((date: Date) => + { + return `${date.getFullYear()}/${('0' + (date.getMonth() + 1)).slice(-2)}/${('0' + date.getDate()).slice(-2)} ` + `${('0' + date.getHours()).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}`; + }, []); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + let startDate = new Date(); + let endDate = new Date(); + + if(trigger.intData[0] > 0) + startDate = new Date((trigger.intData[0] * 1000)); + + if(trigger.intData[1] > 0) + endDate = new Date((trigger.intData[1] * 1000)); + + setStartDate(dateToString(startDate)); + setEndDate(dateToString(endDate)); + } + }, [ trigger ]); + + const save = useCallback(() => + { + let startDateMili = 0; + let endDateMili = 0; + + const startDateInstance = new Date(startDate); + const endDateInstance = new Date(endDate); + + if(startDateInstance && endDateInstance) + { + startDateMili = startDateInstance.getTime() / 1000; + endDateMili = endDateInstance.getTime() / 1000; + } + + setIntParams([startDateMili, endDateMili]); + }, [ startDate, endDate, setIntParams ]); + + return ( + +
{ LocalizeText('wiredfurni.params.startdate') }
+ setStartDate(e.target.value) } /> +
+
{ LocalizeText('wiredfurni.params.enddate') }
+ setEndDate(e.target.value) } /> +
+ ); +}