This commit is contained in:
		
							parent
							
								
									bcd06d894f
								
							
						
					
					
						commit
						e45a3a77ea
					
				| @ -3,7 +3,8 @@ | ||||
|   "cli": { | ||||
|     "schematicCollections": [ | ||||
|       "@angular-eslint/schematics" | ||||
|     ] | ||||
|     ], | ||||
|     "analytics": false | ||||
|   }, | ||||
|   "version": 1, | ||||
|   "newProjectRoot": "projects", | ||||
|  | ||||
| @ -107,6 +107,9 @@ import { | ||||
| import { | ||||
|   RequieredInheritancesCreatorComponent | ||||
| } from "./editor/character-editor/inventory-slot-editor/requiered-inheritances-editor/requiered-inheritances-creator/requiered-inheritances-creator.component"; | ||||
| import { | ||||
|     CharacterInteractionEditorComponent | ||||
| } from "./editor/character-editor/character-interaction-editor/character-interaction-editor.component"; | ||||
| // AoT requires an exported function for factories
 | ||||
| const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader =>  new TranslateHttpLoader(http, './assets/i18n/', '.json'); | ||||
| 
 | ||||
| @ -141,75 +144,76 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader =>  new Transl | ||||
|     InventorySlotCharacteristicEditorComponent, | ||||
|     CharacteristicSelectorComponent, | ||||
|     RequieredInheritancesEditorComponent, | ||||
|     RequieredInheritancesCreatorComponent | ||||
|   ], | ||||
|   imports: [ | ||||
|     BrowserModule, | ||||
|     FormsModule, | ||||
|     HttpClientModule, | ||||
|     CoreModule, | ||||
|     SharedModule, | ||||
|     TranslateModule.forRoot({ | ||||
|       loader: { | ||||
|         provide: TranslateLoader, | ||||
|         useFactory: httpLoaderFactory, | ||||
|         deps: [HttpClient] | ||||
|       } | ||||
|     }), | ||||
|     BrowserAnimationsModule, | ||||
|     MatIcon, | ||||
|     MatToolbar, | ||||
|     MatButton, | ||||
|     MatFormField, | ||||
|     MatInput, | ||||
|     MatDrawerContainer, | ||||
|     MatDrawer, | ||||
|     MatIconButton, | ||||
|     MatMenuTrigger, | ||||
|     MatMenu, | ||||
|     MatMenuItem, | ||||
|     MatListItem, | ||||
|     MatActionList, | ||||
|     MatTabGroup, | ||||
|     MatTab, | ||||
|     MatTabLabel, | ||||
|     MatLabel, | ||||
|     MatFormField, | ||||
|     ReactiveFormsModule, | ||||
|     MatError, | ||||
|     MatDialogTitle, | ||||
|     MatDialogContent, | ||||
|     MatDialogActions, | ||||
|     MatMiniFabButton, | ||||
|     MatTreeModule, | ||||
|     MatTable, | ||||
|     MatColumnDef, | ||||
|     MatHeaderCell, | ||||
|     MatHeaderCellDef, | ||||
|     MatCellDef, | ||||
|     MatCell, | ||||
|     MatHeaderRow, | ||||
|     MatRow, | ||||
|     MatHeaderRowDef, | ||||
|     MatRowDef, | ||||
|     MatCheckbox, | ||||
|     MatSelect, | ||||
|     MatOption, | ||||
|     MatHint, | ||||
|     MatTooltip, | ||||
|     MatCard, | ||||
|     MatCardContent, | ||||
|     MatCardHeader, | ||||
|     MatAccordion, | ||||
|     MatExpansionPanel, | ||||
|     MatExpansionPanelTitle, | ||||
|     MatCardTitle, | ||||
|     MatExpansionPanelHeader, | ||||
|     MatExpansionPanelDescription, | ||||
|     MatAutocomplete, | ||||
|     MatAutocompleteTrigger, | ||||
|     MatNoDataRow | ||||
|     RequieredInheritancesCreatorComponent, | ||||
|     CharacterInteractionEditorComponent | ||||
|   ], | ||||
|     imports: [ | ||||
|         BrowserModule, | ||||
|         FormsModule, | ||||
|         HttpClientModule, | ||||
|         CoreModule, | ||||
|         SharedModule, | ||||
|         TranslateModule.forRoot({ | ||||
|             loader: { | ||||
|                 provide: TranslateLoader, | ||||
|                 useFactory: httpLoaderFactory, | ||||
|                 deps: [HttpClient] | ||||
|             } | ||||
|         }), | ||||
|         BrowserAnimationsModule, | ||||
|         MatIcon, | ||||
|         MatToolbar, | ||||
|         MatButton, | ||||
|         MatFormField, | ||||
|         MatInput, | ||||
|         MatDrawerContainer, | ||||
|         MatDrawer, | ||||
|         MatIconButton, | ||||
|         MatMenuTrigger, | ||||
|         MatMenu, | ||||
|         MatMenuItem, | ||||
|         MatListItem, | ||||
|         MatActionList, | ||||
|         MatTabGroup, | ||||
|         MatTab, | ||||
|         MatTabLabel, | ||||
|         MatLabel, | ||||
|         MatFormField, | ||||
|         ReactiveFormsModule, | ||||
|         MatError, | ||||
|         MatDialogTitle, | ||||
|         MatDialogContent, | ||||
|         MatDialogActions, | ||||
|         MatMiniFabButton, | ||||
|         MatTreeModule, | ||||
|         MatTable, | ||||
|         MatColumnDef, | ||||
|         MatHeaderCell, | ||||
|         MatHeaderCellDef, | ||||
|         MatCellDef, | ||||
|         MatCell, | ||||
|         MatHeaderRow, | ||||
|         MatRow, | ||||
|         MatHeaderRowDef, | ||||
|         MatRowDef, | ||||
|         MatCheckbox, | ||||
|         MatSelect, | ||||
|         MatOption, | ||||
|         MatHint, | ||||
|         MatTooltip, | ||||
|         MatCard, | ||||
|         MatCardContent, | ||||
|         MatCardHeader, | ||||
|         MatAccordion, | ||||
|         MatExpansionPanel, | ||||
|         MatExpansionPanelTitle, | ||||
|         MatCardTitle, | ||||
|         MatExpansionPanelHeader, | ||||
|         MatExpansionPanelDescription, | ||||
|         MatAutocomplete, | ||||
|         MatAutocompleteTrigger, | ||||
|         MatNoDataRow | ||||
|     ], | ||||
|   providers: [], | ||||
|   bootstrap: [AppComponent] | ||||
| }) | ||||
|  | ||||
| @ -66,3 +66,12 @@ | ||||
|     <app-inventory-slot-editor [character]="character" [itemgroups]="gameModel!.itemgroupsAsList"></app-inventory-slot-editor> | ||||
|   </mat-card-content> | ||||
| </mat-card> | ||||
| 
 | ||||
| <mat-card> | ||||
|   <mat-card-header> | ||||
|     <mat-card-title>Character Interactions</mat-card-title> | ||||
|   </mat-card-header> | ||||
|   <mat-card-content> | ||||
|     <app-character-interaction-editor [character]="character" [gameModel]="gameModel"></app-character-interaction-editor> | ||||
|   </mat-card-content> | ||||
| </mat-card> | ||||
|  | ||||
| @ -0,0 +1,109 @@ | ||||
| <table mat-table [dataSource]="interactionDatasource" multiTemplateDataRows class="mat-elevation-z8"> | ||||
|   <ng-container matColumnDef="sequence"> | ||||
|     <th mat-header-cell *matHeaderCellDef>Sequence</th> | ||||
|     <td mat-cell *matCellDef="let interaction"> | ||||
|       @if(isInteractionSequence(interaction)) { | ||||
|         <mat-icon>done</mat-icon> | ||||
|       } @else { | ||||
|         <mat-icon>close</mat-icon> | ||||
|       } | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <ng-container matColumnDef="source"> | ||||
|     <th mat-header-cell *matHeaderCellDef>Source</th> | ||||
|     <td mat-cell *matCellDef="let interaction"> | ||||
|       @if(interaction != editedElement) { | ||||
|         {{interaction.sourceCharacter.componentName}} | ||||
|       } @else { | ||||
|         <mat-form-field appearance="fill" class="long-form"> | ||||
|           <mat-label>Source Character</mat-label> | ||||
|           <mat-select [(ngModel)]="editedElement!.sourceCharacter"> | ||||
|             <mat-option *ngFor="let character of gameModel!.characters" [value]="character">{{character.componentName}}</mat-option> | ||||
|           </mat-select> | ||||
|         </mat-form-field> | ||||
|       } | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <ng-container matColumnDef="target"> | ||||
|     <th mat-header-cell *matHeaderCellDef>Target</th> | ||||
|     <td mat-cell *matCellDef="let interaction"> | ||||
|       @if(interaction != editedElement) { | ||||
|         @if(interaction.targetCharacter != undefined) { | ||||
|           {{interaction!.targetCharacter!.componentName}} | ||||
|         } @else { | ||||
|           <p class="warning">UNKNOWN CHARACTER</p> | ||||
|         } | ||||
|       } @else { | ||||
|         <mat-form-field appearance="fill" class="long-form"> | ||||
|           <mat-label>Target Character</mat-label> | ||||
|           <mat-select [(ngModel)]="editedElement!.targetCharacter"> | ||||
|             <mat-option *ngFor="let character of gameModel!.characters" [value]="character">{{character.componentName}}</mat-option> | ||||
|           </mat-select> | ||||
|         </mat-form-field> | ||||
|       } | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <ng-container matColumnDef="label"> | ||||
|     <th mat-header-cell *matHeaderCellDef>Label</th> | ||||
|     <td mat-cell *matCellDef="let interaction"> | ||||
|       @if(interaction != editedElement) { | ||||
|         {{interaction.interactionLabel}} | ||||
|       } @else { | ||||
|         <mat-form-field appearance="fill" class="long-form"> | ||||
|           <mat-label>Label</mat-label> | ||||
|           <input matInput [(ngModel)]="editedElement!.interactionLabel"> | ||||
|         </mat-form-field> | ||||
|       } | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <ng-container matColumnDef="edit"> | ||||
|     <th mat-header-cell *matHeaderCellDef></th> | ||||
|     <td mat-cell *matCellDef="let interaction"> | ||||
|       <button mat-icon-button *ngIf="editedElement !== interaction" [disabled]="editedElement != null" (click)="editInteraction(interaction)"><mat-icon>edit</mat-icon></button> | ||||
|       <button mat-icon-button *ngIf="editedElement === interaction" (click)="submitInteraction()"><mat-icon>done</mat-icon></button> | ||||
|     </td> | ||||
|   </ng-container> | ||||
|   <ng-container matColumnDef="delete"> | ||||
|     <th mat-header-cell *matHeaderCellDef></th> | ||||
|     <td mat-cell *matCellDef="let interaction"> | ||||
|       <button mat-icon-button color="warn" (click)="deleteInteraction(interaction)"><mat-icon>delete</mat-icon></button> | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <ng-container matColumnDef="expand"> | ||||
|     <th mat-header-cell *matHeaderCellDef aria-label="row actions"> | ||||
|       <button mat-icon-button (click)="addInteraction()"><mat-icon>add</mat-icon></button> | ||||
|     </th> | ||||
|     <td mat-cell *matCellDef="let element"> | ||||
|       <button mat-icon-button aria-label="expand row" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()"> | ||||
|         @if (expandedElement === element) { | ||||
|           <mat-icon>keyboard_arrow_up</mat-icon> | ||||
|         } @else { | ||||
|           <mat-icon>keyboard_arrow_down</mat-icon> | ||||
|         } | ||||
|       </button> | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns --> | ||||
|   <ng-container matColumnDef="expandedDetail"> | ||||
|     <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length"> | ||||
|       <div class="example-element-detail" | ||||
|            [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'"> | ||||
|         <p>Expanded Detail</p> | ||||
|       </div> | ||||
|     </td> | ||||
|   </ng-container> | ||||
| 
 | ||||
|   <tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr> | ||||
|   <tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;" | ||||
|       class="example-element-row" | ||||
|       [class.example-expanded-row]="expandedElement === element" | ||||
|       (click)="expandedElement = expandedElement === element ? null : element"> | ||||
|   </tr> | ||||
|   <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr> | ||||
| </table> | ||||
| @ -0,0 +1,55 @@ | ||||
| table { | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| tr.example-detail-row { | ||||
|   height: 0; | ||||
| } | ||||
| 
 | ||||
| tr.example-element-row:not(.example-expanded-row):hover { | ||||
|   background: #4e5157; | ||||
| } | ||||
| 
 | ||||
| tr.example-element-row:not(.example-expanded-row):active { | ||||
|   background: #545456; | ||||
| } | ||||
| 
 | ||||
| .example-element-row td { | ||||
|   border-bottom-width: 0; | ||||
| } | ||||
| 
 | ||||
| .example-element-detail { | ||||
|   overflow: hidden; | ||||
|   display: flex; | ||||
| } | ||||
| 
 | ||||
| .example-element-diagram { | ||||
|   min-width: 80px; | ||||
|   border: 2px solid black; | ||||
|   padding: 8px; | ||||
|   font-weight: lighter; | ||||
|   margin: 8px 0; | ||||
|   height: 104px; | ||||
| } | ||||
| 
 | ||||
| .example-element-symbol { | ||||
|   font-weight: bold; | ||||
|   font-size: 40px; | ||||
|   line-height: normal; | ||||
| } | ||||
| 
 | ||||
| .example-element-description { | ||||
|   padding: 16px; | ||||
| } | ||||
| 
 | ||||
| .example-element-description-attribution { | ||||
|   opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .mat-column-delete, .mat-column-edit, .mat-column-expand, .mat-column-sequence { | ||||
|   width: 32px; | ||||
| } | ||||
| 
 | ||||
| .warning { | ||||
|   color: red; | ||||
| } | ||||
| @ -0,0 +1,23 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { CharacterInteractionEditorComponent } from './character-interaction-editor.component'; | ||||
| 
 | ||||
| describe('CharacterInteractionEditorComponent', () => { | ||||
|   let component: CharacterInteractionEditorComponent; | ||||
|   let fixture: ComponentFixture<CharacterInteractionEditorComponent>; | ||||
| 
 | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       imports: [CharacterInteractionEditorComponent] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|      | ||||
|     fixture = TestBed.createComponent(CharacterInteractionEditorComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
| 
 | ||||
|   it('should create', () => { | ||||
|     expect(component).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,78 @@ | ||||
| import {Component, Input, OnInit} from '@angular/core'; | ||||
| import {Character} from "../../../project/game-model/characters/Character"; | ||||
| import {GameModel} from "../../../project/game-model/GameModel"; | ||||
| import {AbstractInteraction} from "../../../project/game-model/interactions/AbstractInteraction"; | ||||
| import {MatColumnDef, MatTable, MatTableDataSource} from "@angular/material/table"; | ||||
| import {InteractionSequences} from "../../../project/game-model/interactions/InteractionSequences"; | ||||
| import {animate, state, style, transition, trigger} from "@angular/animations"; | ||||
| import {Interaction} from "../../../project/game-model/interactions/Interaction"; | ||||
| import {Condition} from "../../../project/game-model/interactions/condition/Condition"; | ||||
| import {MatSnackBar} from "@angular/material/snack-bar"; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-character-interaction-editor', | ||||
|   templateUrl: './character-interaction-editor.component.html', | ||||
|   styleUrl: './character-interaction-editor.component.scss', | ||||
|   animations: [ | ||||
|     trigger('detailExpand', [ | ||||
|       state('collapsed,void', style({height: '0px', minHeight: '0'})), | ||||
|       state('expanded', style({height: '*'})), | ||||
|       transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), | ||||
|     ]), | ||||
|   ], | ||||
| }) | ||||
| export class CharacterInteractionEditorComponent implements OnInit{ | ||||
| 
 | ||||
|   @Input() character: Character | undefined | ||||
|   @Input() gameModel: GameModel | undefined | ||||
| 
 | ||||
|   displayedColumns: string[] = ['sequence', 'source', 'target', 'label', 'edit', 'delete'] | ||||
|   columnsToDisplayWithExpand = [... this.displayedColumns, 'expand']; | ||||
|   expandedElement: AbstractInteraction | null = null; | ||||
|   editedElement: AbstractInteraction | null = null; | ||||
| 
 | ||||
|   interactionDatasource: MatTableDataSource<AbstractInteraction> = new MatTableDataSource(); | ||||
| 
 | ||||
|   constructor(private snackbar: MatSnackBar) { | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   ngOnInit() { | ||||
|     this.interactionDatasource.data = this.gameModel!.getCharacterInteractionsByCharacter(this.character!); | ||||
|   } | ||||
| 
 | ||||
|   isInteractionSequence(interaction: AbstractInteraction) { | ||||
|     return interaction instanceof InteractionSequences | ||||
|   } | ||||
| 
 | ||||
|   addInteraction() { | ||||
|     const interaction = new Interaction(this.character!, undefined, "") | ||||
|     this.editedElement = interaction; | ||||
| 
 | ||||
|     const interactions = this.interactionDatasource.data; | ||||
|     interactions.push(interaction); | ||||
|     this.interactionDatasource.data = interactions; | ||||
|   } | ||||
| 
 | ||||
|   submitInteraction() { | ||||
|     if(this.editedElement == undefined) { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if(this.editedElement!.validate(this.character!)) { | ||||
|       this.gameModel!.addCharacterInteraction(this.editedElement); | ||||
|       this.editedElement = null; | ||||
|     } else { | ||||
|       this.snackbar.open("Invalid Interaction", "", {duration: 2000}); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   deleteInteraction(interaction: AbstractInteraction) { | ||||
|     this.gameModel!.removeCharacterInteraction(interaction); | ||||
|     this.interactionDatasource.data = this.gameModel!.characterInteractions; | ||||
|   } | ||||
| 
 | ||||
|   editInteraction(interaction: AbstractInteraction) { | ||||
|     this.editedElement = interaction; | ||||
|   } | ||||
| } | ||||
| @ -17,6 +17,7 @@ import {ConcreteItemGroup} from "./inventory/ConcreteItemGroup"; | ||||
| import {Item} from "./inventory/Item"; | ||||
| import {ItemgroupUtilities} from "./utils/ItemgroupUtilities"; | ||||
| import {ItemGroupCharacteristic} from "./inventory/ItemgroupCharacteristic"; | ||||
| import {AbstractInteraction} from "./interactions/AbstractInteraction"; | ||||
| 
 | ||||
| export class GameModel { | ||||
|   gameModelName: string | ||||
| @ -25,6 +26,7 @@ export class GameModel { | ||||
|   scriptAccounts: ScriptAccount[] = []; | ||||
|   characters: Character[] = [] | ||||
|   itemgroups: ItemGroup[] = [] | ||||
|   characterInteractions: AbstractInteraction[] = [] | ||||
| 
 | ||||
|   constructor(gameModelName: string) { | ||||
|     this.gameModelName = gameModelName; | ||||
| @ -240,4 +242,18 @@ export class GameModel { | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   getCharacterInteractionsByCharacter(character: Character) { | ||||
|     return this.characterInteractions.filter(interaction => interaction.targetCharacter === character || interaction.sourceCharacter === character); | ||||
|   } | ||||
| 
 | ||||
|   addCharacterInteraction(characterInteraction: AbstractInteraction) { | ||||
|     if(this.characterInteractions.find(interaction => interaction.equals(characterInteraction)) == undefined) { | ||||
|       this.characterInteractions.push(characterInteraction); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   removeCharacterInteraction(characterInteraction: AbstractInteraction) { | ||||
|     this.characterInteractions = this.characterInteractions.filter(interaction => interaction != characterInteraction); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -3,16 +3,19 @@ import {Condition} from "./condition/Condition"; | ||||
| 
 | ||||
| export abstract class AbstractInteraction { | ||||
|   sourceCharacter: Character | ||||
|   targetCharacter: Character | ||||
|   targetCharacter: Character | undefined | ||||
| 
 | ||||
|   conditions: Condition[] = [] | ||||
| 
 | ||||
|   interactionLabel: string | ||||
| 
 | ||||
| 
 | ||||
|   constructor(sourceCharacter: Character, targetCharacter: Character, interactionLabel: string) { | ||||
|   constructor(sourceCharacter: Character, targetCharacter: Character | undefined, interactionLabel: string) { | ||||
|     this.sourceCharacter = sourceCharacter; | ||||
|     this.targetCharacter = targetCharacter; | ||||
|     this.interactionLabel = interactionLabel; | ||||
|   } | ||||
| 
 | ||||
|   abstract equals(other: AbstractInteraction): boolean | ||||
|   abstract validate(requieredCharacter: Character): boolean | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,31 @@ export class Interaction extends AbstractInteraction{ | ||||
|   actions: Action[] = [] | ||||
| 
 | ||||
| 
 | ||||
|   constructor(sourceCharacter: Character, targetCharacter: Character, interactionLabel: string) { | ||||
|   constructor(sourceCharacter: Character, targetCharacter: Character | undefined, interactionLabel: string) { | ||||
|     super(sourceCharacter, targetCharacter, interactionLabel); | ||||
|   } | ||||
| 
 | ||||
|   equals(other: AbstractInteraction): boolean { | ||||
|     if(!(other instanceof Interaction)) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     const equealCharacters = this.sourceCharacter === other.sourceCharacter && this.targetCharacter === other.targetCharacter; | ||||
|     const equalLabels = this.interactionLabel === other.interactionLabel; | ||||
|     const equalConditions = this.conditions.every(condition => other.conditions.includes(condition)) && other.conditions.every(condition => this.conditions.includes(condition)); | ||||
| 
 | ||||
|     const equalActions = this.actions.every(action => other.actions.includes(action) && other.actions.every(action => this.actions.includes(action))); | ||||
| 
 | ||||
|     return equealCharacters && equalLabels && equalConditions && equalActions; | ||||
|   } | ||||
| 
 | ||||
|   validate(requieredCharacter: Character): boolean { | ||||
|     const validCharacters = this.sourceCharacter == requieredCharacter || this.targetCharacter == requieredCharacter; | ||||
|     const validLabel = this.interactionLabel.length > 0; | ||||
|     //Todo: Check for contradicting conditions as well as double conditions and actions
 | ||||
| 
 | ||||
|     return validCharacters && validLabel; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -4,10 +4,68 @@ import {Character} from "../characters/Character"; | ||||
| 
 | ||||
| export class InteractionSequences extends AbstractInteraction { | ||||
| 
 | ||||
|   interactions: Interaction[] = [] | ||||
|   rootInteraction: InteractionSequenceNode | ||||
| 
 | ||||
| 
 | ||||
|   constructor(sourceCharacter: Character, targetCharacter: Character, interactionLabel: string) { | ||||
|     super(sourceCharacter, targetCharacter, interactionLabel); | ||||
|   constructor(interaction: Interaction, interactionLabel: string) { | ||||
|     super(interaction.sourceCharacter, interaction.targetCharacter, interactionLabel); | ||||
|     this.rootInteraction = new InteractionSequenceNode(interaction, []); | ||||
|   } | ||||
| 
 | ||||
|   equals(other: AbstractInteraction): boolean { | ||||
|     if(!(other instanceof InteractionSequences)) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     const equealCharacters = this.sourceCharacter === other.sourceCharacter && this.targetCharacter === other.targetCharacter; | ||||
|     const equalLabels = this.interactionLabel === other.interactionLabel; | ||||
|     const equalConditions = this.conditions.every(condition => other.conditions.includes(condition)) && other.conditions.every(condition => this.conditions.includes(condition)); | ||||
| 
 | ||||
|     const equalSequenceTree = this.rootInteraction.equals(other.rootInteraction); | ||||
| 
 | ||||
|     return equealCharacters && equalLabels && equalConditions && equalSequenceTree; | ||||
|   } | ||||
| 
 | ||||
|   validate(requieredCharacter: Character): boolean { | ||||
|     const validCharacters = this.sourceCharacter == requieredCharacter || this.targetCharacter == requieredCharacter; | ||||
|     const validLabel = this.interactionLabel.length > 0; | ||||
|     const validSequenceTree = this.rootInteraction.validate(requieredCharacter) | ||||
| 
 | ||||
|     return validCharacters && validLabel && validSequenceTree; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class InteractionSequenceNode { | ||||
| 
 | ||||
|   root: Interaction | ||||
|   children: InteractionSequenceNode[] = []; | ||||
| 
 | ||||
|   equals(other: InteractionSequenceNode) { | ||||
|     const equalsRoot = this.root.equals(other.root); | ||||
|     const equalsChildren = this.children.every(child => other.children.includes(child) && other.children.every(child => this.children.includes(child))); | ||||
| 
 | ||||
|     return equalsRoot && equalsChildren; | ||||
|   } | ||||
| 
 | ||||
|   validate(requiredCharacter: Character): boolean { | ||||
|     const validateRoot = this.root.validate(requiredCharacter); | ||||
|     let validateChildren = true; | ||||
| 
 | ||||
|     for(let i=0; i<this.children.length; i++) { | ||||
|       if(!this.children[i].validate(requiredCharacter)) { | ||||
|         validateChildren = false; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     return validateRoot && validateChildren; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   constructor(root: Interaction, children: InteractionSequenceNode[]) { | ||||
|     this.root = root; | ||||
|     this.children = children; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -21,3 +21,7 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } | ||||
| .icon-btn-primary { | ||||
|   color: #3c95f8; | ||||
| } | ||||
| 
 | ||||
| .long-form { | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user