Files
habitica/website/client/src/components/avatar.vue
2021-03-23 11:58:21 -05:00

298 lines
8.2 KiB
Vue

<template>
<div
class="avatar"
:style="{width, height, paddingTop}"
:class="backgroundClass"
@click.prevent="castEnd()"
>
<div
class="character-sprites"
:style="{margin: spritesMargin}"
>
<template v-if="!avatarOnly">
<!-- Mount Body-->
<span
v-if="member.items.currentMount"
:class="'Mount_Body_' + member.items.currentMount"
></span>
</template>
<!-- Buffs that cause visual changes to avatar: Snowman, Ghost, Flower, etc-->
<template v-for="(klass, item) in visualBuffs">
<span
v-if="member.stats.buffs[item] && showVisualBuffs"
:key="item"
:class="klass"
></span>
</template>
<!-- Show flower ALL THE TIME!!!-->
<!-- See https://github.com/HabitRPG/habitica/issues/7133-->
<span :class="'hair_flower_' + member.preferences.hair.flower"></span>
<!-- Show avatar only if not currently affected by visual buff-->
<template v-if="showAvatar()">
<span :class="['chair_' + member.preferences.chair, specialMountClass]"></span>
<span :class="[getGearClass('back'), specialMountClass]"></span>
<span :class="[skinClass, specialMountClass]"></span>
<!-- eslint-disable max-len-->
<span
:class="[member.preferences.size + '_shirt_' + member.preferences.shirt, specialMountClass]"
></span>
<!-- eslint-enable max-len-->
<span :class="['head_0', specialMountClass]"></span>
<!-- eslint-disable max-len-->
<span :class="[member.preferences.size + '_' + getGearClass('armor'), specialMountClass]"></span>
<!-- eslint-enable max-len-->
<span :class="[getGearClass('back_collar'), specialMountClass]"></span>
<template
v-for="type in ['bangs', 'base', 'mustache', 'beard']"
>
<!-- eslint-disable max-len-->
<span
:key="type"
:class="['hair_' + type + '_' + member.preferences.hair[type] + '_' + member.preferences.hair.color, specialMountClass]"
></span>
<!-- eslint-enable max-len-->
</template>
<span :class="[getGearClass('body'), specialMountClass]"></span>
<span :class="[getGearClass('eyewear'), specialMountClass]"></span>
<span :class="[getGearClass('head'), specialMountClass]"></span>
<span :class="[getGearClass('headAccessory'), specialMountClass]"></span>
<span :class="['hair_flower_' + member.preferences.hair.flower, specialMountClass]"></span>
<span
v-if="!hideGear('shield')"
:class="[getGearClass('shield'), specialMountClass]"
></span>
<span
v-if="!hideGear('weapon')"
:class="[getGearClass('weapon'), specialMountClass]"
></span>
</template>
<!-- Resting-->
<span
v-if="member.preferences.sleep"
class="zzz"
></span>
<template v-if="!avatarOnly">
<!-- Mount Head-->
<span
v-if="member.items.currentMount"
:class="'Mount_Head_' + member.items.currentMount"
></span>
<!-- Pet-->
<span
v-if="member.items.currentPet"
class="current-pet"
:class="petClass"
></span>
</template>
</div>
<class-badge
v-if="hasClass && !hideClassBadge"
class="under-avatar"
:member-class="member.stats.class"
/>
</div>
</template>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.avatar {
width: 141px;
height: 147px;
image-rendering: pixelated;
position: relative;
cursor: pointer;
}
.character-sprites {
width: 90px;
height: 90px;
}
.character-sprites span {
position: absolute;
}
.current-pet {
bottom: 0px;
left: 0px;
}
.offset-kangaroo {
margin-top: 24px;
}
.invert {
filter: invert(100%);
}
</style>
<script>
import some from 'lodash/some';
import moment from 'moment';
import { mapState } from '@/libs/store';
import ClassBadge from '@/components/members/classBadge';
export default {
components: {
ClassBadge,
},
props: {
member: {
type: Object,
required: true,
},
avatarOnly: {
type: Boolean,
default: false,
},
hideClassBadge: {
type: Boolean,
default: false,
},
withBackground: {
type: Boolean,
},
overrideAvatarGear: {
type: Object,
},
width: {
type: Number,
default: 140,
},
height: {
type: Number,
default: 147,
},
spritesMargin: {
type: String,
default: '0 auto 0 24px',
},
overrideTopPadding: {
type: String,
},
showVisualBuffs: {
type: Boolean,
default: true,
},
},
computed: {
...mapState({
flatGear: 'content.gear.flat',
currentEventList: 'worldState.data.currentEventList',
}),
hasClass () {
return this.$store.getters['members:hasClass'](this.member);
},
isBuffed () {
return this.$store.getters['members:isBuffed'](this.member);
},
paddingTop () {
if (this.overrideTopPadding) {
return this.overrideTopPadding;
}
let val = '24px';
if (!this.avatarOnly) {
if (this.member.items.currentPet) val = '24px';
if (this.member.items.currentMount) val = '0px';
}
return val;
},
backgroundClass () {
const { background } = this.member.preferences;
const allowToShowBackground = !this.avatarOnly || this.withBackground;
if (this.overrideAvatarGear && this.overrideAvatarGear.background) {
return `background_${this.overrideAvatarGear.background}`;
}
if (background && allowToShowBackground) {
return `background_${this.member.preferences.background}`;
}
return '';
},
visualBuffs () {
return {
snowball: `avatar_snowball_${this.member.stats.class}`,
spookySparkles: 'ghost',
shinySeed: `avatar_floral_${this.member.stats.class}`,
seafoam: 'seafoam_star',
};
},
skinClass () {
const baseClass = `skin_${this.member.preferences.skin}`;
return `${baseClass}${this.member.preferences.sleep ? '_sleep' : ''}`;
},
costumeClass () {
return this.member.preferences.costume ? 'costume' : 'equipped';
},
specialMountClass () {
if (!this.avatarOnly && this.member.items.currentMount && this.member.items.currentMount.includes('Kangaroo')) {
return 'offset-kangaroo';
}
return null;
},
petClass () {
if (some(
this.currentEventList,
event => moment().isBetween(event.start, event.end) && event.aprilFools && event.aprilFools === 'invert',
)) {
return `Pet-${this.member.items.currentPet} invert`;
}
return `Pet-${this.member.items.currentPet}`;
},
},
methods: {
getGearClass (gearType) {
let result = this.member.items.gear[this.costumeClass][gearType];
if (this.overrideAvatarGear && this.overrideAvatarGear[gearType]) {
result = this.overrideAvatarGear[gearType];
}
return result;
},
hideGear (gearType) {
if (gearType === 'weapon') {
const equippedWeapon = this.member.items.gear[this.costumeClass][gearType];
if (!equippedWeapon) {
return false;
}
const equippedIsTwoHanded = this.flatGear[equippedWeapon].twoHanded;
const hasOverrideShield = this.overrideAvatarGear && this.overrideAvatarGear.shield;
return equippedIsTwoHanded && hasOverrideShield;
} if (gearType === 'shield') {
const overrideWeapon = this.overrideAvatarGear && this.overrideAvatarGear.weapon;
const overrideIsTwoHanded = overrideWeapon && this.flatGear[overrideWeapon].twoHanded;
return overrideIsTwoHanded;
}
return false;
},
castEnd (e) {
if (!this.$store.state.spellOptions.castingSpell) return;
this.$root.$emit('castEnd', this.member, 'user', e);
},
showAvatar () {
if (!this.showVisualBuffs) return true;
const { buffs } = this.member.stats;
return !buffs.snowball && !buffs.spookySparkles && !buffs.shinySeed && !buffs.seafoam;
},
},
};
</script>