Merge conflicts

This commit is contained in:
Bill 2021-06-30 00:38:43 -04:00
commit 06af222057
8 changed files with 373 additions and 7 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -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;
}
}

View File

@ -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 <WiredActionChatView />;
case WiredActionLayout.FLEE:
return <WiredActionFleeView />;
case WiredActionLayout.GIVE_REWARD:
return <WiredActionGiveRewardView />;
case WiredActionLayout.GIVE_SCORE:
return <WiredActionGiveScoreView />;
case WiredActionLayout.GIVE_SCORE_TO_PREDEFINED_TEAM:

View File

@ -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 <WiredConditionActorIsWearingEffectView />;
case WiredConditionlayout.DATE_RANGE_ACTIVE:
return <WiredConditionDateRangeView />;
case WiredConditionlayout.FURNIS_HAVE_AVATARS:
case WiredConditionlayout.FURNI_NOT_HAVE_HABBO:
return <WiredConditionFurniHasAvatarOnView />;

View File

@ -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 (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="limitEnabled" onChange={(e) => setLimitEnabled(e.target.checked)} />
<label className="form-check-label" htmlFor="uniqueRewards">
{ LocalizeText('wiredfurni.params.prizelimit', ['amount'], [limitEnabled ? rewardsLimit.toString() : '']) }
</label>
</div>
{ !limitEnabled && <div className="bg-muted rounded small text-black p-1 text-center">
Reward limit not set. Make sure rewards are badges or non-tradeable items.
</div> }
{ limitEnabled && <Slider
defaultValue={ rewardsLimit }
dots={ true }
min={ 1 }
max={ 1000 }
step={ 1 }
onChange={ event => setRewardsLimit(event) }
/> }
<hr className="my-1 mb-2 bg-dark" />
<div className="fw-bold">How ofter can a user be rewarded?</div>
<div className="d-flex">
<select className="form-select form-select-sm w-100" value={ rewardTime } onChange={ (e) => setRewardTime(Number(e.target.value)) }>
<option value="0">Once</option>
<option value="3">Once every { limitationInterval } minutes</option>
<option value="2">Once every { limitationInterval } hours</option>
<option value="1">Once every { limitationInterval } days</option>
</select>
{ rewardTime > 0 && <input type="number" className="ms-2 form-control form-control-sm" value={ limitationInterval } onChange={ event => setLimitationInterval(Number(event.target.value)) } /> }
</div>
<hr className="my-1 mb-2 bg-dark" />
<div className="form-check">
<input className="form-check-input" type="checkbox" id="uniqueRewards" checked={ uniqueRewards } onChange={(e) => setUniqueRewards(e.target.checked)} />
<label className="form-check-label" htmlFor="uniqueRewards">
Unique rewards
</label>
</div>
<div className="bg-muted rounded small text-black p-1 text-center">If checked each reward will be given once to each user. This will disable the probabilities option.</div>
<hr className="my-1 mb-2 bg-dark" />
<div className="d-flex justify-content-between align-items-center">
<div className="fw-bold">Rewards</div>
<div className="btn btn-sm btn-success" onClick={ addReward }><i className="fas fa-plus" /></div>
</div>
<table className="table-sm">
<thead>
<tr>
<td>Badge?</td>
<td>Item Code</td>
<td>Probability</td>
<td></td>
</tr>
</thead>
<tbody>
{ rewards && rewards.map((reward, index) =>
{
return (
<tr key={ index }>
<td className="d-flex align-items-center justify-content-center">
<input className="form-check-input" type="checkbox" checked={ reward.isBadge } onChange={(e) => updateReward(index, e.target.checked, reward.itemCode, reward.probability)} />
</td>
<td>
<input type="text" className="form-control form-control-sm" value={ reward.itemCode } onChange={ e => updateReward(index, reward.isBadge, e.target.value, reward.probability) } />
</td>
<td>
<input type="number" className="form-control form-control-sm" value={ reward.probability } onChange={ e => updateReward(index, reward.isBadge, reward.itemCode, Number(e.target.value)) } />
</td>
<td>
{ index > 0 && <button className="btn btn-sm btn-danger" onClick={() => removeReward(index) }><i className="fas fa-trash" /></button> }
</td>
</tr>
)
}) }
</tbody>
</table>
</WiredActionBaseView>
);
}

View File

@ -54,7 +54,7 @@ export const WiredActionMoveAndRotateFurniView: FC<{}> = props =>
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.startdir') }</label>
<div className="row row-cold-4">
<div className="row row-col-4">
{ directionOptions.map(option =>
{
return (

View File

@ -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<WiredBaseViewProps> = props =>
}, [ setTrigger ]);
return (
<NitroCardView className="nitro-wired" simple={ true }>
<NitroCardHeaderView headerText={ LocalizeText('wiredfurni.title') } onCloseClick={ close } />
<NitroCardContentView className="text-black">
<NitroCardView className={`nitro-wired nitro-wired-${wiredType} ` + (wiredType == 'trigger' ? 'rounded-0' : 'rounded-2')}>
<div className="nitro-wired-header d-flex">
<div className="nitro-wired-title rounded-start w-100 drag-handler">{LocalizeText('wiredfurni.title')}</div>
<div className="nitro-wired-close rounded-end flex-shrink-0" onClick={ close }><i className="fas fa-times" /></div>
</div>
<NitroCardContentView>
<div className="d-flex align-items-center">
<i className={ `me-2 icon icon-wired-${ wiredType }` } />
<div className="fw-bold">{ wiredName }</div>
@ -73,8 +76,8 @@ export const WiredBaseView: FC<WiredBaseViewProps> = props =>
<div>{ LocalizeText('wiredfurni.pickfurnis.desc') }</div>
</> }
<div className="d-flex mt-3">
<button className="btn btn-success btn-sm me-2 w-100" onClick={ onSave }>{ LocalizeText('wiredfurni.ready') }</button>
<button className="btn btn-secondary btn-sm w-100" onClick={ close }>{ LocalizeText('cancel') }</button>
<button className="btn btn-sm btn-success me-2 w-100" onClick={ onSave }>{ LocalizeText('wiredfurni.ready') }</button>
<button className="btn btn-sm btn-secondary w-100" onClick={ close }>{ LocalizeText('cancel') }</button>
</div>
</NitroCardContentView>
</NitroCardView>

View File

@ -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 (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="fw-bold">{ LocalizeText('wiredfurni.params.startdate') }</div>
<input type="text" className="form-control form-control-sm" value={ startDate } onChange={ (e) => setStartDate(e.target.value) } />
<hr className="my-1 mb-2 bg-dark" />
<div className="fw-bold">{ LocalizeText('wiredfurni.params.enddate') }</div>
<input type="text" className="form-control form-control-sm" value={ endDate } onChange={ (e) => setEndDate(e.target.value) } />
</WiredConditionBaseView>
);
}