tgd-frontend/src/app/views/onboarding/onboarding.component.ts
2024-11-28 01:31:02 +04:00

177 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { animate, keyframes, style, transition, trigger } from '@angular/animations';
import { Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { take, takeUntil } from 'rxjs/operators';
import { getAudioPath } from 'src/app/helper/tts.helper';
import { VoiceService } from "../../services/voice.service";
interface RuleItem {
text: string;
action?: () => void;
voice?: number;
screpa?: boolean;
hideWithoutVoice?: boolean;
}
@Component({
selector: 'app-onboarding',
templateUrl: './onboarding.component.html',
styleUrls: ['./onboarding.component.scss'],
animations: [
trigger('fadeInAnimation', [
transition('void => *', []), // when the item is created
transition('* => void', []), // when the item is removed
transition('* => *', [ // when the item is changed
animate(1200, keyframes([ // animate for 1200 ms
style ({ opacity: 0.0}),
style ({ opacity: 1.0 }),
])),
]),
])]
})
export class OnboardingComponent implements OnInit, OnDestroy {
@ViewChild('avoidPenaltyCard') private avoidPenaltyCardEl: ElementRef;
@ViewChild('stolePrizeCard') private stolePrizeCardEl: ElementRef;
@ViewChild('versusCard') private versusCardEl: ElementRef;
@ViewChild('luckyCard') private luckyCardEl: ElementRef;
@ViewChild('banPlayerCard') private banPlayerEl: ElementRef;
@ViewChild('doubleTreasureCard') private doubleTreasureCardEl: ElementRef;
private rules: RuleItem[] = [
{ text: 'Игра состоит из вопросов с четырьмя вариантами ответов, правильный - только один.'},
{ text: 'Вопросы и ответы будут отображаться на экране и в Боте Благодарения.' },
{ text: 'Каждый игрок в начале игры имеет на руках 4 карты, набор карт определяется случайно. Описание карт ты найдешь ниже. После использования карты ты получаешь новую случайную карту.' },
{ text: 'На разыгрывание карты время ограничено, примерно 10 секунд.' },
{ text: 'Вы долго просили оптимизировать геймплей для медленных и глупых, и мы это сделали!'},
{ text: 'Задача игрока - ответить правильно и быстрее других, ну или хотя бы просто правильно в течение 20 секунд' },
{ text: 'Первый игрок, ответивший правильно, получает два очка' },
{ text: 'Все остальные, ответившие правильно, получают одно очко'},
{ text: 'Иногда за неправильные ответы игроки будут получать наказания' },
{ text: 'Избежать наказания можно только с помощью соотвествуещей карты, данную карту ты можешь сыграть перед озвучиванием наказания', action: () => {
this.shakeCard(this.avoidPenaltyCardEl);
}},
{ text: 'Карту "украсть приз" ты можешь сыграть в момент, когда кто-то собирается получить награду, но до момента того, как ты узнаешь, что это именно за приз', action: () => {
this.shakeCard(this.stolePrizeCardEl);
}},
{ text: 'Карту "Поединок" ты можешь разыграть в любой момент, чтобы вызвать игрока на дуэль', action: () => {
this.shakeCard(this.versusCardEl);
}},
{ text: '"Лаки карту" ты сможешь сыграть после своего правильного ответа, она увеличит твои шансы на получение приза', action: () => {
this.shakeCard(this.luckyCardEl);
}},
{
text: 'Карту бана можно сыграть на любого игрока (даже себя), чтобы отправить его на пару ходов во Владикавказ. Игрок не сможет участвовать в случайном количестве раундов',
action: () => {
this.shakeCard(this.banPlayerEl);
}
},
{
text: 'Ну и самая редкая карта - карта удвоения приза, играй ее перед тем, как получить награду, и вместо одной награды ты получишь две!',
action: () => {
this.shakeCard(this.doubleTreasureCardEl);
}
},
{ text: 'Не торопись с ответами, игра идет до той поры, пока мы не разыграем все призы' },
{
text: 'Ах да, так как создатель игры, работает на Microsoft, мы добавили привычные вам баги, но все их оставим в секрете',
},
{
text: 'Кажется, правила закончились'
}
];
public currentRule: string;
private currentRulePosition = 0;
private allRulesAnnounced = false;
private destroyed$ = new Subject<void>();
private voiceSubscription: Subscription;
public screpaText = '';
public showScrepa = false;
constructor(private voiceService: VoiceService, private renderer: Renderer2) { }
ngOnInit(): void {
this.voiceService.playAudio(getAudioPath('Итак, друзья, перейдем к правилам'));
setTimeout(() => {
this.beginRuleSwitching();
}, 3500);
}
ngOnDestroy(): void {
this.destroyed$.complete();
this.voiceSubscription?.unsubscribe();
}
shakeCard(card: ElementRef) {
this.renderer.addClass(card.nativeElement, 'shake');
this.renderer.addClass(card.nativeElement, 'zoom-in');
if(!this.allRulesAnnounced) {
this.voiceService.audioEndedSubject
.pipe(takeUntil(this.destroyed$),take(1))
.subscribe(() => {
this.renderer.addClass(card.nativeElement, 'zoom-out');
setTimeout(() => {
this.renderer.removeClass(card.nativeElement, 'zoom-out');
this.renderer.removeClass(card.nativeElement, 'zoom-in');
}, 3000);
this.stopShaking(card);
})
} else {
setTimeout(() => {
this.renderer.removeClass(card.nativeElement, 'zoom-out');
this.renderer.removeClass(card.nativeElement, 'zoom-in');
}, 5000);
this.stopShaking(card);
}
}
stopShaking(card: ElementRef) {
this.renderer.removeClass(card.nativeElement, 'shake');
}
private handleRule(rule: RuleItem) {
if(this.currentRulePosition > this.rules.length) {
this.currentRulePosition = 0;
}
console.log(`handle rule ${this.currentRulePosition}`);
this.currentRule = rule.screpa ? this.currentRule : rule.text.replace(/(?<=\[)(.*?)(?=\])/, '').replace('[','').replace(']','')
if (!this.allRulesAnnounced) {
const voice = rule.voice ? rule.voice : 1;
this.showScrepa = !!rule.screpa;
this.screpaText = rule.text;
this.voiceService.playAudio(getAudioPath(rule.text, voice));
} else {
if(rule.hideWithoutVoice || rule.screpa) {
this.playNextRule();
}
}
if (rule.action) {
rule.action();
}
}
private playNextRule() {
this.currentRulePosition++;
if (this.currentRulePosition === this.rules.length && !this.allRulesAnnounced) {
this.allRulesAnnounced = true;
this.voiceService.playAudio(getAudioPath(`Это все правила, надеюсь, все понятно. А если нет - сейчас Кирилл и Оксана вам все пояснят,
ну и совсем для тупых - пустила по кругу правила на экране,
а если ты их не поймешь - то очень жаль тебя глупенького`));
this.voiceService.audioEndedSubject.pipe(takeUntil(this.destroyed$),take(1)).subscribe(() => {
setInterval(() => { this.playNextRule() }, 6000);
this.currentRulePosition = 0
});
} else {
this.handleRule(this.rules[this.currentRulePosition]);
}
}
private beginRuleSwitching() {
this.handleRule(this.rules[this.currentRulePosition]);
this.voiceSubscription = this.voiceService.audioEndedSubject.pipe(takeUntil(this.destroyed$)).subscribe(() => {
setTimeout(() => this.playNextRule(), 500);
console.log(`audioEnded`);
})
}
}