2018-04-10 21:13:34 -04:00
< template lang = "html" >
< div class = "ffz--experiments tw-pd-t-05" >
2018-04-11 17:05:31 -04:00
< div class = "tw-pd-b-1 tw-mg-b-1 tw-border-b" >
2018-04-28 17:56:03 -04:00
{ { t ( 'setting.experiments.about' , 'This feature allows you to override experiment values. Please note that, for most experiments, you may have to refresh the page for your changes to take effect.' ) } }
2018-04-10 21:13:34 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< section v-if = "experiments_locked" >
< div class = "tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-2" >
< h3 class = "ffz-i-attention" >
{ { t ( 'setting.dev-warning' , "It's dangerous to go at all." ) } }
< / h3 >
< markdown : source = "t('setting.dev-warning.explain', 'Be careful, this is an advanced feature intended for developer use only. Normal users should steer clear. Adjusting your experiments can have unexpected impacts on your Twitch experience. FrankerFaceZ is not responsible for any issues you encounter as a result of tampering with experiments, and we will not provide support.\n\nIf you\'re sure about this, please type `sv_cheats 1` into the box below and hit enter.')" / >
< / div >
< div class = "tw-flex tw-align-items-center" >
< input
ref = "code"
type = "text"
class = "tw-block tw-full-width tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-x-1 tw-pd-y-05"
autocapitalize = "off"
autocorrect = "off"
@ keydown . enter = "enterCode"
>
< / div >
< / section >
< section v-else >
< div class = "tw-mg-b-2 tw-flex tw-align-items-center" >
< div class = "tw-flex-grow-1" >
{ { t ( 'setting.experiments.unique-id' , 'Unique ID: {id}' , { id : unique _id } ) } }
< / div >
< select
ref = "sort_select"
class = "tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-x-05"
@ change = "onSort"
>
< option : selected = "sort_by === 0" >
{ { t ( 'setting.experiments.sort-name' , 'Sort By: Name' ) } }
< / option >
< option : selected = "sort_by === 1" >
{ { t ( 'setting.experiments.sort-rarity' , 'Sort By: Rarity' ) } }
< / option >
< / select >
< / div >
< div class = "tw-mg-b-2 tw-flex tw-align-items-center" >
< div class = "tw-flex-grow-1" / >
< div class = "tw-checkbox tw-relative" >
< input
id = "unused"
ref = "unused"
v - model = "unused"
type = "checkbox"
class = "tw-checkbox__input"
>
< label for = "unused" class = "tw-checkbox__label" >
< span class = "tw-mg-l-1" >
{ { t ( 'setting.experiments.show-unused' , 'Display unused experiments.' ) } }
< / span >
< / label >
< / div >
2018-04-11 17:05:31 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< h3 class = "tw-mg-b-1" >
< span >
{ { t ( 'setting.experiments.ffz' , 'FrankerFaceZ Experiments' ) } }
< / span >
< span v-if = "filter" class="tw-mg-l-1 tw-font-size-base tw-regular tw-c-text-alt-2" >
{ { t ( 'setting.experiments.visible' , '(Showing {visible,number} of {total,number})' , {
visible : visible _ffz . length ,
total : sorted _ffz . length
} ) } }
< / span >
< / h3 >
< div class = "ffz--experiment-list" >
< section
v - for = "({key, exp}) of visible_ffz"
: key = "key"
: data - key = "key"
>
< div class = "tw-elevation-1 tw-c-background-base tw-border tw-pd-y-05 tw-pd-x-1 tw-mg-y-05 tw-flex tw-flex-nowrap" >
< div class = "tw-flex-grow-1" >
< h4 > { { exp . name } } < / h4 >
< div v-if = "exp.description" class="description" >
{ { exp . description } }
< / div >
2018-04-10 21:13:34 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< div class = "tw-flex tw-flex-shrink-0 tw-align-items-start" >
< select
: data - key = "key"
class = "tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-x-05"
@ change = "onChange($event)"
>
< option
v - for = "(i, idx) in exp.groups"
: key = "idx"
: selected = "i.value === exp.value"
>
{ { t ( 'setting.experiments.entry' , '{value,tostring} (weight: {weight,tostring})' , i ) } }
< / option >
< / select >
< button
: disabled = "exp.default"
: class = "{'tw-button--disabled': exp.default}"
2020-12-17 16:51:26 -05:00
class = "tw-mg-t-05 tw-button tw-button--text tw-tooltip__container"
2020-07-01 19:07:17 -04:00
@ click = "reset(key)"
2018-04-10 21:13:34 -04:00
>
2020-07-01 19:07:17 -04:00
< span class = "tw-button__text ffz-i-cancel" / >
< span class = "tw-tooltip tw-tooltip--down tw-tooltip--align-right" >
{ { t ( 'setting.reset' , 'Reset to Default' ) } }
< / span >
< / button >
< / div >
2018-04-10 21:13:34 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< / section >
< div v-if = "! Object.keys(ffz_data).length" >
{ { t ( 'setting.experiments.none' , 'There are no current experiments.' ) } }
< / div >
< div v -else -if = " ! visible_ffz.length " >
{ { t ( 'setting.experiments.none-filter' , 'There are no matching experiments.' ) } }
2018-04-10 21:13:34 -04:00
< / div >
2020-05-27 15:44:37 -04:00
< / div >
2018-04-10 21:13:34 -04:00
2020-07-01 19:07:17 -04:00
< h3 class = "tw-mg-t-5 tw-mg-b-1" >
< span >
{ { t ( 'setting.experiments.twitch' , 'Twitch Experiments' ) } }
< / span >
< span v-if = "filter" class="tw-mg-l-1 tw-font-size-base tw-regular tw-c-text-alt-2" >
{ { t ( 'setting.experiments.visible' , '(Showing {visible,number} of {total,number})' , {
visible : visible _twitch . length ,
total : sorted _twitch . length
} ) } }
< / span >
< / h3 >
< div class = "ffz--experiment-list" >
< section
v - for = "({key, exp}) of visible_twitch"
: key = "key"
: data - key = "key"
2018-04-10 21:13:34 -04:00
>
2020-07-01 19:07:17 -04:00
< div
: class = "{live: exp.in_use}"
class = "ffz--experiment-row tw-elevation-1 tw-c-background-base tw-border tw-pd-y-05 tw-pd-x-1 tw-mg-y-05 tw-flex"
>
< div v-if = "unused" class="tw-flex tw-flex-shrink-0 tw-align-items-center tw-border-r tw-mg-r-1 tw-pd-r-1" >
2020-12-17 16:51:26 -05:00
< div v-if = "exp.in_use" class="ffz--profile__icon ffz-i-ok tw-tooltip__container" >
2020-07-01 19:07:17 -04:00
< div class = "tw-tooltip tw-tooltip--down tw-tooltip--align-left" >
{ { t ( 'setting.experiments.active' , 'This experiment is active.' ) } }
< / div >
2018-04-10 21:13:34 -04:00
< / div >
2020-12-17 16:51:26 -05:00
< div v -else class = "ffz--profile__icon ffz-i-cancel tw-tooltip__container" >
2020-07-01 19:07:17 -04:00
< div class = "tw-tooltip tw-tooltip--down tw-tooltip--align-left" >
{ { t ( 'setting.experiments.inactive' , 'This experiment is not active.' ) } }
< / div >
2018-04-10 21:13:34 -04:00
< / div >
< / div >
2020-07-01 19:07:17 -04:00
< div class = "tw-flex-grow-1" >
< h4 > { { exp . name } } < / h4 >
< div class = "description" >
{ { exp . remainder } }
< / div >
2018-04-10 21:13:34 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< div class = "tw-flex tw-flex-shrink-0 tw-align-items-start" >
< select
: data - key = "key"
class = "tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-x-05"
@ change = "onTwitchChange($event)"
2018-04-11 17:05:31 -04:00
>
2020-07-01 19:07:17 -04:00
< option
v - if = "exp.in_use === false"
: selected = "exp.default"
>
{ { t ( 'setting.experiments.unset' , 'unset' ) } }
< / option >
< option
v - for = "(i, idx) in exp.groups"
: key = "idx"
: selected = "i.value === exp.value"
>
{ { t ( 'setting.experiments.entry' , '{value,tostring} (weight: {weight,tostring})' , i ) } }
< / option >
< / select >
< button
: disabled = "exp.default"
: class = "{'tw-button--disabled': exp.default}"
2020-12-17 16:51:26 -05:00
class = "tw-mg-t-05 tw-button tw-button--text tw-tooltip__container"
2020-07-01 19:07:17 -04:00
@ click = "resetTwitch(key)"
2018-04-10 21:13:34 -04:00
>
2020-07-01 19:07:17 -04:00
< span class = "tw-button__text ffz-i-cancel" / >
< span class = "tw-tooltip tw-tooltip--down tw-tooltip--align-right" >
{ { t ( 'setting.reset' , 'Reset to Default' ) } }
< / span >
< / button >
< / div >
2018-04-10 21:13:34 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< / section >
< div v-if = "! Object.keys(twitch_data).length" >
{ { t ( 'setting.experiments.none' , 'There are no current experiments.' ) } }
< / div >
< div v -else -if = " ! visible_twitch.length " >
{ { t ( 'setting.experiments.none-filter' , 'There are no matching experiments.' ) } }
2018-04-10 21:13:34 -04:00
< / div >
2020-05-27 15:44:37 -04:00
< / div >
2020-07-01 19:07:17 -04:00
< / section >
2018-04-10 21:13:34 -04:00
< / div >
< / template >
< script >
import { has } from 'utilities/object' ;
2020-05-27 15:44:37 -04:00
function matches ( exp , filter ) {
return ( exp . key && exp . key . toLowerCase ( ) . includes ( filter ) ) ||
( exp . exp && (
( exp . exp . name && exp . exp . name . toLowerCase ( ) . includes ( filter ) ) ||
( exp . exp . description && exp . exp . description . toLowerCase ( ) . includes ( filter ) )
) ) ;
}
2018-04-10 21:13:34 -04:00
export default {
2020-05-27 15:44:37 -04:00
props : [ 'item' , 'filter' ] ,
2018-04-10 21:13:34 -04:00
data ( ) {
return {
2020-07-01 19:07:17 -04:00
experiments _locked : this . item . is _locked ( ) ,
2018-04-11 17:05:31 -04:00
sort _by : 1 ,
2020-07-01 19:07:17 -04:00
unused : false ,
2018-04-11 17:05:31 -04:00
unique _id : this . item . unique _id ( ) ,
2018-04-10 21:13:34 -04:00
ffz _data : this . item . ffz _data ( ) ,
twitch _data : this . item . twitch _data ( )
}
} ,
2020-05-27 15:44:37 -04:00
computed : {
sorted _ffz ( ) {
return this . sorted ( this . ffz _data ) ;
} ,
visible _ffz ( ) {
const items = this . sorted _ffz ,
f = this . filter && this . filter . toLowerCase ( ) ;
if ( ! f )
return items ;
return items . filter ( x => matches ( x , f ) ) ;
} ,
sorted _twitch ( ) {
return this . sorted ( this . twitch _data ) ;
} ,
visible _twitch ( ) {
const items = this . sorted _twitch ,
f = this . filter && this . filter . toLowerCase ( ) ;
if ( ! f )
return items ;
return items . filter ( x => matches ( x , f ) ) ;
}
} ,
2018-04-10 21:13:34 -04:00
created ( ) {
for ( const key in this . ffz _data )
if ( has ( this . ffz _data , key ) ) {
const exp = this . ffz _data [ key ] ;
this . $set ( exp , 'value' , this . item . getAssignment ( key ) ) ;
this . $set ( exp , 'default' , ! this . item . hasOverride ( key ) ) ;
2018-04-11 17:05:31 -04:00
exp . total = exp . groups . reduce ( ( a , b ) => a + b . weight , 0 ) ;
this . calculateRarity ( exp ) ;
2018-04-10 21:13:34 -04:00
}
for ( const key in this . twitch _data )
if ( has ( this . twitch _data , key ) ) {
const exp = this . twitch _data [ key ] ;
this . $set ( exp , 'value' , this . item . getTwitchAssignment ( key ) ) ;
this . $set ( exp , 'default' , ! this . item . hasTwitchOverride ( key ) ) ;
exp . in _use = this . item . usingTwitchExperiment ( key ) ;
2020-08-29 13:06:17 -04:00
exp . remainder = ` v: ${ exp . v } , type: ${ this . item . getTwitchType ( exp . t ) } ` ;
2018-04-11 17:05:31 -04:00
exp . total = exp . groups . reduce ( ( a , b ) => a + b . weight , 0 ) ;
this . calculateRarity ( exp ) ;
2018-04-10 21:13:34 -04:00
}
this . item . on ( ':changed' , this . valueChanged , this ) ;
this . item . on ( ':twitch-changed' , this . twitchValueChanged , this ) ;
} ,
beforeDestroy ( ) {
this . item . off ( ':changed' , this . valueChanged , this ) ;
this . item . off ( ':twitch-changed' , this . twitchValueChanged , this ) ;
} ,
methods : {
2020-07-01 19:07:17 -04:00
enterCode ( ) {
if ( this . $refs . code . value !== 'sv_cheats 1' )
return ;
this . experiments _locked = false ;
this . item . unlock ( ) ;
} ,
2018-04-11 17:05:31 -04:00
calculateRarity ( exp ) {
let rarity ;
for ( const group of exp . groups )
if ( group . value === exp . value ) {
rarity = group . weight / exp . total ;
break ;
}
this . $set ( exp , 'rarity' , rarity ) ;
} ,
2018-04-10 21:13:34 -04:00
sorted ( data ) {
2020-07-01 19:07:17 -04:00
const out = [ ] ;
for ( const [ k , v ] of Object . entries ( data ) ) {
if ( ! this . unused && v . in _use === false )
continue ;
out . push ( { key : k , exp : v } ) ;
}
//const out = Object.entries(data).map(x => ({key: x[0], exp: x[1]}));
2018-04-10 21:13:34 -04:00
out . sort ( ( a , b ) => {
const a _use = a . exp . in _use ,
b _use = b . exp . in _use ;
if ( a _use && ! b _use ) return - 1 ;
if ( ! a _use && b _use ) return 1 ;
2018-04-11 17:05:31 -04:00
if ( this . sort _by === 1 ) {
const a _r = a . exp . rarity ,
b _r = b . exp . rarity ;
if ( a _r < b _r ) return - 1 ;
if ( a _r > b _r ) return 1 ;
}
2018-04-10 21:13:34 -04:00
const a _n = a . exp . name . toLowerCase ( ) ,
b _n = b . exp . name . toLowerCase ( ) ;
if ( a _n < b _n ) return - 1 ;
if ( a _n > b _n ) return 1 ;
2018-04-11 17:05:31 -04:00
2018-04-10 21:13:34 -04:00
return 0 ;
} ) ;
return out ;
} ,
reset ( key ) {
this . item . deleteOverride ( key ) ;
const exp = this . ffz _data [ key ] ;
if ( exp )
exp . default = ! this . item . hasOverride ( key ) ;
} ,
resetTwitch ( key ) {
this . item . deleteTwitchOverride ( key ) ;
const exp = this . twitch _data [ key ] ;
if ( exp )
exp . default = ! this . item . hasTwitchOverride ( key ) ;
} ,
2018-04-11 17:05:31 -04:00
onSort ( ) {
this . sort _by = this . $refs . sort _select . selectedIndex ;
} ,
2018-04-10 21:13:34 -04:00
onChange ( event ) {
const el = event . target ,
idx = el . selectedIndex ,
key = el . dataset . key ;
const exp = this . ffz _data [ key ] ,
groups = exp && exp . groups ,
entry = groups && groups [ idx ] ;
if ( entry )
this . item . setOverride ( key , entry . value ) ;
} ,
onTwitchChange ( event ) {
const el = event . target ,
idx = el . selectedIndex ,
key = el . dataset . key ;
const exp = this . twitch _data [ key ] ,
2018-04-11 17:05:31 -04:00
offset = exp . in _use ? 0 : 1 ,
2018-04-10 21:13:34 -04:00
groups = exp && exp . groups ,
2018-04-11 17:05:31 -04:00
entry = groups && groups [ idx - offset ] ;
2018-04-10 21:13:34 -04:00
if ( entry )
this . item . setTwitchOverride ( key , entry . value ) ;
} ,
valueChanged ( key , value ) {
const exp = this . ffz _data [ key ] ;
if ( exp ) {
exp . value = value ;
exp . default = ! this . item . hasOverride ( key ) ;
2018-04-11 17:05:31 -04:00
this . calculateRarity ( exp ) ;
2018-04-10 21:13:34 -04:00
}
} ,
twitchValueChanged ( key , value ) {
const exp = this . twitch _data [ key ] ;
if ( exp ) {
exp . value = value ;
exp . default = ! this . item . hasTwitchOverride ( key ) ;
2018-04-11 17:05:31 -04:00
this . calculateRarity ( exp ) ;
2018-04-10 21:13:34 -04:00
}
}
}
}
< / script >