Commit c431957c authored by Romain DELEAU's avatar Romain DELEAU

verification + favicon

parent 6bb93da2
......@@ -165,6 +165,9 @@
<div>{{'language_en' | translate}}</div>
</button>
</mat-menu>
<button mat-mini-fab color="white" (click)="verifyGame()"
[matTooltip]="translate.instant('verify_tooltip')"
matTooltipPosition="above" [matTooltipDisabled]="!tooltipService.activatedTooltips"><mat-icon fontIcon="verified"></mat-icon></button>
<button mat-mini-fab color="white" (click)="downloadManual()"
[matTooltip]="translate.instant('manual_tooltip')"
matTooltipPosition="above" [matTooltipDisabled]="!tooltipService.activatedTooltips"><mat-icon fontIcon="menu_book"></mat-icon></button>
......
......@@ -201,7 +201,7 @@
&-secondline {
top: 75px;
width: 112px;
width: 176px;
right: 360px;
}
}
......
......@@ -37,6 +37,8 @@ import Minimap from 'js-minimap';
import { MinimapService } from './services/minimap/minimap.service';
import { TranslateService } from '@ngx-translate/core';
import { TutorialService } from './services/tutorial/tutorial.service';
import { VerifyGameFailSnackbarComponent } from './components/snackbars/verify-game-fail-snackbar/verify-game-fail-snackbar.component';
import { VerifyDialogComponent } from './components/dialogs/verify-dialog/verify-dialog.component';
@Component({
selector: 'app-root',
......@@ -431,4 +433,39 @@ export class AppComponent {
resumeTutorialTrace() {
this.scenario.traces.push(new Trace(this.scenario.traces.length, 'resume_tutorial', undefined, undefined, 'phase_'+this.tutorialService.phase, 'Tutorial'));
}
verifyIfAllDurationUnitAreSame(): boolean {
let res = true;
let durationUnit: string;
this.scenario.missions.forEach(mission => {
mission.roles.forEach(role => {
for (let i = 0; i < role.tasks.length; i++) {
for (let j = 0; j < role.tasks[i].length; j++) {
let task: Task|null = role.tasks[i][j];
if (task instanceof Task) {
if (durationUnit) {
if (durationUnit != task.durationUnit) {
res = false;
}
} else {
durationUnit = task.durationUnit;
}
}
}
}
});
});
return res;
}
verifyGame(): void {
if (this.verifyIfAllDurationUnitAreSame()) {
const dialogRef = this.dialog.open(VerifyDialogComponent, {
data: this.scenario
});
} else {
this._snackBar.openFromComponent(VerifyGameFailSnackbarComponent, { duration: 10000 });
}
}
}
\ No newline at end of file
......@@ -48,6 +48,8 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TutorialComponent } from './components/tutorial/tutorial.component';
import { FinishTutorialComponent } from './components/snackbars/finish-tutorial/finish-tutorial.component';
import { VerifyGameFailSnackbarComponent } from './components/snackbars/verify-game-fail-snackbar/verify-game-fail-snackbar.component';
import { VerifyDialogComponent } from './components/dialogs/verify-dialog/verify-dialog.component';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http);
......@@ -87,7 +89,9 @@ export function HttpLoaderFactory(http: HttpClient) {
LoadingsucessSnackbarComponent,
LoadingfailSnackbarComponent,
TutorialComponent,
FinishTutorialComponent
FinishTutorialComponent,
VerifyGameFailSnackbarComponent,
VerifyDialogComponent
],
imports: [
BrowserModule,
......
......@@ -154,6 +154,7 @@ export class Role {
return res;
}
/*
getRealIndex(i: number, j: number): number {
let realj: number = 0;
let index: number = 0;
......@@ -178,8 +179,30 @@ export class Role {
index++;
}
}
return realj;
}
*/
getRealIndex(i: number, j: number): number {
let realj: number = 0;
for(let k = 0; k < j; k++) {
let task: Task|null = this.tasks[i][k];
if (task instanceof Task) {
if (task.durationUnit == 'UT') {
if (task.duration <= 10) {
realj += task.duration;
} else {
realj =+ 10;
}
} else {
realj++;
}
} else {
realj++;
}
}
console.log(realj);
return realj;
}
......
<!--
<h2 mat-dialog-title>{{'dialog_clear_title' | translate}}</h2>
<mat-dialog-content>{{'dialog_clear_content' | translate}} ?</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>{{'dialog_button_no' | translate}}</button>
<button mat-button [mat-dialog-close]="true" cdkFocusInitial>{{'dialog_button_yes' | translate}}</button>
</mat-dialog-actions>
-->
<!--
<mat-dialog-content>
<div *ngFor="let mission of scenario.missions, let missionIndex = index">
<div *ngFor="let symbol of getMissionSymbols(mission), let symbolIndex = index">
<div *ngFor="let role of mission.roles, let roleIndex = index">
<div *ngIf="verifyRoleSymbolsMax(role,roleIndex,symbol) > 0">
min{{verifyRoleSymbolsMin(role,roleIndex,symbol)}} max{{verifyRoleSymbolsMax(role,roleIndex,symbol)}}
<mat-icon [fontIcon]="getAsSymbol(symbol[0]).symbol" [style.color]="getAsSymbol(symbol[0]).color"></mat-icon>
</div>
</div>
</div>
<div *ngFor="let role of mission.roles, let roleIndex = index">
min{{verifyRolesMin(role)}} max{{verifyRoleMax(role)}}
</div>
</div>
</mat-dialog-content>
-->
<h1 mat-dialog-title>{{'verify_title' | translate}}</h1>
<mat-dialog-content>
<div class="info">
<p>{{'verify_info_title' | translate}}</p>
<p>{{'verify_info_content_part1' | translate}}<br/>{{'verify_info_content_part2' | translate}}</p>
</div>
<div class="mission" *ngFor="let mission of scenario.missions, let missionIndex = index">
<h3>Mission {{missionIndex + 1}}</h3>
<div class="mission-symbol" *ngFor="let symbol of getMissionSymbols(mission), let symbolIndex = index">
<div *ngFor="let role of mission.roles, let roleIndex = index">
<div *ngFor="let symbol2 of getRoleSymbolsAndIndex(mission)">
<p *ngIf="getAsSymbol(symbol2[0]).symbol == symbol.symbol && getAsSymbol(symbol2[0]).color == symbol.color && verifyRoleSymbolsMax(role,roleIndex,symbol2)">
[{{getRoleName(missionIndex,roleIndex)}}] {{'verify_role_symbol_part1' | translate}} [{{verifyRoleSymbolsMin(role,roleIndex,symbol2)}} {{getDurationUnit()}}] {{'verify_role_symbol_part2' | translate}} [{{verifyRoleSymbolsMax(role,roleIndex,symbol2)}} {{getDurationUnit()}}]
{{'verify_role_symbol_part3' | translate}} [<mat-icon [fontIcon]="getAsSymbol(symbol2[0]).symbol" [style.color]="getAsSymbol(symbol2[0]).color"></mat-icon>]
</p>
</div>
</div>
</div>
<div class="mission-role">
<p *ngFor="let role of mission.roles, let roleIndex = index">
{{'verify_role_part1' | translate}} [{{getRoleName(missionIndex,roleIndex)}}] {{'verify_role_part2' | translate}} [{{verifyRolesMin(role)}} {{getDurationUnit()}}] {{'verify_role_part3' | translate}} [{{verifyRoleMax(role)}} {{getDurationUnit()}}]
</p>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>{{'verify_leave_button' | translate}}</button>
</mat-dialog-actions>
\ No newline at end of file
h1, h2, h3 {
font-family: 'Glacial Indifference Bold', sans-serif;
}
button {
margin-top: 20px;
}
mat-dialog-content {
font-size: 16px;
}
.info {
padding-bottom: 20px;
border-bottom: solid 1px black;
}
.mission {
margin-bottom: 50px;
&-symbol {
mat-icon {
position: relative;
top: 50%;
transform: translateY(40%);
}
}
&-role {
margin-top: 20px;
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { VerifyDialogComponent } from './verify-dialog.component';
describe('VerifyDialogComponent', () => {
let component: VerifyDialogComponent;
let fixture: ComponentFixture<VerifyDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ VerifyDialogComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(VerifyDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Scenario } from 'src/app/class/scenario/scenario';
import { Mission } from 'src/app/class/mission/mission';
import { Role } from 'src/app/class/role/role';
import { Symbol } from 'src/app/class/symbol/symbol';
import { Task } from 'src/app/class/task/task';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'app-verify-dialog',
templateUrl: './verify-dialog.component.html',
styleUrls: ['./verify-dialog.component.scss']
})
export class VerifyDialogComponent implements OnInit {
durationUnit: string = '';
constructor(@Inject(MAT_DIALOG_DATA) public scenario: Scenario, protected translate: TranslateService) {
}
ngOnInit(): void {
}
getAsSymbol(symbol: any): Symbol {
return symbol as Symbol;
}
getMissionSymbols(mission: Mission): Symbol[] {
let symbols: Symbol[] = [];
mission.roles.forEach(role => {
for (let i = 0; i < role.tasks.length; i++) {
for (let j = 0; j < role.tasks[i].length; j++) {
let task: Task|null = role.tasks[i][j];
if (task instanceof Task && task.symbol.symbol && task.symbol.color && !symbols.some(symbol => task?.symbol.symbol == symbol.symbol && task.symbol.color == symbol.color)) {
symbols.push(task.symbol);
}
}
}
});
return symbols;
}
getRoleSymbolsAndIndex(mission: Mission): (Symbol|number)[][] {
let symbols: (Symbol|number)[][] = []; // [0] => Symbol / [1] => role / [2] => visualIndex
mission.roles.forEach((role, roleIndex) => {
for (let i = 0; i < role.tasks.length; i++) {
for (let j = 0; j < role.tasks[i].length; j++) {
let task: Task|null = role.tasks[i][j];
if (task instanceof Task && task.symbol.symbol && task.symbol.color) {
symbols.push([task.symbol, roleIndex, role.getRealIndex(i,j)]);
}
}
}
});
return symbols;
}
verifyRoleSymbolsMin(role: Role, roleIndex: number, symbolInfo: (Symbol | number)[]): number {
let symbol: Symbol = symbolInfo[0] as Symbol;
let symbolRoleIndex: number = symbolInfo[1] as number;
let taskIndex: number = symbolInfo[2] as number;
let time: number = 0;
let optionnalUT: number[][] = []; //[[column,ut,ut,ut],[column,ut,ut]];
if (roleIndex == symbolRoleIndex) {
for (let i = 0; i < role.tasks.length; i++) {
let j: number = 0;
while (role.getRealIndex(i, j) < taskIndex) {
let task: Task | null = role.tasks[i][j];
if (task instanceof Task && task?.type != 'repeat' && task?.type != 'annexe' && task.symbol != symbol) {
if (task?.type == 'optionnal') {
let realj: number = role.getRealIndex(i, j);
if (optionnalUT.some(element => element[0] == realj)) {
optionnalUT[optionnalUT.findIndex(element => element[0] == realj)].push((task as Task).duration);
} else {
optionnalUT.push([realj, (task as Task).duration]);
}
} else {
time = time + (task as Task).duration;
}
}
j++;
}
}
optionnalUT.forEach(optionnalTasks => {
let min: number = optionnalTasks[1];
for (let k = 2; k < optionnalTasks.length; k++) {
if (optionnalTasks[k] < min) {
min = optionnalTasks[k];
}
}
time = time + min;
});
}
return time;
}
verifyRoleSymbolsMax(role: Role, roleIndex: number, symbolInfo: (Symbol | number)[]): number {
let symbol: Symbol = symbolInfo[0] as Symbol;
let symbolRoleIndex: number = symbolInfo[1] as number;
let taskIndex: number = symbolInfo[2] as number;
let time: number = 0;
if (symbolRoleIndex == roleIndex) {
for (let i = 0; i < role.tasks.length; i++) {
let j: number = 0;
while (role.getRealIndex(i, j) <= taskIndex) {
let task: Task | null = role.tasks[i][j];
if (task instanceof Task && task?.type != 'repeat' && task.symbol != symbol) {
time = time + (role.tasks[i][j] as Task).duration;
}
j++;
}
}
}
return time;
}
verifyRolesMin(role: Role): number {
let time: number = 0;
let optionnalUT: number[][] = []; //[[column,ut,ut,ut],[column,ut,ut]];
for (let i = 0; i < role.tasks.length; i++) {
for (let j = 0; j < role.tasks[i].length; j++) {
if (role.tasks[i][j] instanceof Task && role.tasks[i][j]?.type != 'repeat' && role.tasks[i][j]?.type != 'annexe') {
if (role.tasks[i][j]?.type == 'optionnal') {
let realj: number = role.getRealIndex(i, j);
if (optionnalUT.some(element => element[0] == realj)) {
optionnalUT[optionnalUT.findIndex(element => element[0] == realj)].push((role.tasks[i][j] as Task).duration);
} else {
optionnalUT.push([realj, (role.tasks[i][j] as Task).duration]);
}
} else {
time = time + (role.tasks[i][j] as Task).duration;
}
if (!this.durationUnit) {
this.durationUnit = (role.tasks[i][j] as Task).durationUnit;
}
}
}
}
optionnalUT.forEach(optionnalTasks => {
let min: number = optionnalTasks[1];
for (let k = 2; k < optionnalTasks.length; k++) {
if (optionnalTasks[k] < min) {
min = optionnalTasks[k];
}
}
time = time + min;
});
return time;
}
verifyRoleMax(role: Role): number {
let time: number = 0;
for (let i = 0; i < role.tasks.length; i++) {
for (let j = 0; j < role.tasks[i].length; j++) {
if (role.tasks[i][j] instanceof Task && role.tasks[i][j]?.type != 'repeat') {
time = time + (role.tasks[i][j] as Task).duration;
}
}
}
return time;
}
getRoleName(missionIndex: number, roleIndex: number): string {
let name: string = this.translate.instant('role_title')+' '+(roleIndex+1);
if (this.scenario.missions[missionIndex].roles[roleIndex].intitule) {
name = this.scenario.missions[missionIndex].roles[roleIndex].intitule;
}
return name;
}
getDurationUnit(): string {
let durationUnit: string = this.translate.instant('step_duration_ut');
switch(this.durationUnit) {
case 'UT': durationUnit = this.translate.instant('step_duration_ut'); break;
case 'min': durationUnit = this.translate.instant('step_duration_min'); break;
case 'tours': durationUnit = this.translate.instant('step_duration_turn'); break;
}
return durationUnit;
}
}
<span matSnackBarLabel>{{'verify_error' | translate}}</span>
\ No newline at end of file
::ng-deep .mat-snack-bar-container {
background-color: #de3e44;
color: white;
box-shadow: 0px 0px 15px 5px #de3e44;
text-align: center;
}
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { VerifyGameFailSnackbarComponent } from './verify-game-fail-snackbar.component';
describe('VerifyGameFailSnackbarComponent', () => {
let component: VerifyGameFailSnackbarComponent;
let fixture: ComponentFixture<VerifyGameFailSnackbarComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ VerifyGameFailSnackbarComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(VerifyGameFailSnackbarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-verify-game-fail-snackbar',
templateUrl: './verify-game-fail-snackbar.component.html',
styleUrls: ['./verify-game-fail-snackbar.component.scss']
})
export class VerifyGameFailSnackbarComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
......@@ -20,6 +20,7 @@
"download_tooltip": "Download a backup of the scenario.",
"upload_tooltip": "Import a backup of the scenario.",
"manual_tooltip": "Download the user manual (FR).",
"verify_tooltip": "Verify the scenario",
"lang_tooltip": "Change the language.",
"snackbar_identifier": "Attention, this identifier is already used in this Role.",
......@@ -318,5 +319,18 @@
"tutorial_optionnal_occurence": "Role Occurrence",
"tutorial_optionnalPhase_occurence": "This allows you to define, when the number of players is greater than the number of roles, the distribution of players among the different roles. To define this, click on a Role tile.",
"tutorial_optionnal_comments": "Comments",
"tutorial_optionnalPhase_comments": "This allows you to add any information you deem important to specify on any tile. To add a comment, click on a tile, and the comments will be present in the sidebar."
"tutorial_optionnalPhase_comments": "This allows you to add any information you deem important to specify on any tile. To add a comment, click on a tile, and the comments will be present in the sidebar.",
"verify_title": "Here are the feasibility verification details for your scenario:",
"verify_error": "Warning, you have not entered the same time units for all tasks, so it is impossible to verify the scenario",
"verify_info_title": "Your scenario is feasible and balanced if:",
"verify_info_content_part1": "- It is possible for all roles with the same common task to access it at the same time. For example, if Role 1 requires between 3 and 5 TU to access it, and Role 2 requires between 4 and 6 TU, then the task is achievable.",
"verify_info_content_part2": "- All roles can finish their quest at the same time (same number of TU).",
"verify_role_symbol_part1": "needs between",
"verify_role_symbol_part2": "and",
"verify_role_symbol_part3": "to acceed to the common task",
"verify_role_part1": "The quest of",
"verify_role_part2": "needs between",
"verify_role_part3": "and",
"verify_leave_button": "OK"
}
\ No newline at end of file
......@@ -20,6 +20,7 @@
"download_tooltip": "Télécharger une sauvegarde du scénario.",
"upload_tooltip": "Importer une sauvegarde du scénario.",
"manual_tooltip": "Télécharger le manuel d'utilisation",
"verify_tooltip": "Vérifier le scénario",
"lang_tooltip": "Changer la langue.",
"snackbar_identifier": "Attention, cet identifiant est déjà utilisé dans ce Rôle",
......@@ -318,5 +319,18 @@
"tutorial_optionnal_occurence": "Occurence du Rôle",
"tutorial_optionnalPhase_occurence": "Ceci permet de définir lorsque le nombre de joueur est supérieur au nombre de rôles, la répartition des joueurs au sein des différents rôles. Pour définir cela, cliquez sur une tuile Rôle.",
"tutorial_optionnal_comments": "Commentaires",
"tutorial_optionnalPhase_comments": "Ceci permet d'ajouter tout élément qui vous semble important de préciser sur n'importe quelle tuile. Pour ajouter un commentaire, cliquez sur une tuile et les commentaires seront présents dans la barre latérale."
"tutorial_optionnalPhase_comments": "Ceci permet d'ajouter tout élément qui vous semble important de préciser sur n'importe quelle tuile. Pour ajouter un commentaire, cliquez sur une tuile et les commentaires seront présents dans la barre latérale.",
"verify_title": "Voici les informations de vérification de faisabilité de votre scénario :",
"verify_error": "Attention, vous n'avez pas saisi les mêmes unités de temps sur toutes les tâches, il est donc impossible de vérifier le scénario",
"verify_info_title": "Votre scénario est réalisable et équilibré si :",
"verify_info_content_part1": "- Il est possible pour tous les rôles ayant la même tâche commune d'y accéder au même moment. Par exemple si pour le Rôle 1 il faut entre 3 et 5 UT pour y accéder, et qu'il faut entre 4 et 6 UT pour le Rôle 2, alors la tâche est réalisable.",
"verify_info_content_part2": "- Tous les Rôles peuvent terminer leur quête en même temps (même nombre d'UT).",
"verify_role_symbol_part1": "met entre",
"verify_role_symbol_part2": "et",
"verify_role_symbol_part3": "pour accéder à la tâche commune",
"verify_role_part1": "La quête de",
"verify_role_part2": "met entre",
"verify_role_part3": "et",
"verify_leave_button": "OK"
}
\ No newline at end of file
src/favicon.ico

948 Bytes | W: | H:

src/favicon.ico

1.07 KB | W: | H:

src/favicon.ico
src/favicon.ico
src/favicon.ico
src/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment