SES-159 #78
@ -50,6 +50,9 @@ import { GameMasterMonstersTableComponent } from './components/game-master-monst
|
||||
import { MonsterService } from '../services/monster.service';
|
||||
import { SpellDetailsDialogComponent } from './components/spell-details-dialog/spell-details-dialog.component';
|
||||
import { GameMasterShopkeepersTableComponent } from './components/game-master-shopkeepers-table/game-master-shopkeepers-table.component';
|
||||
import { GameMasterTurntrackerComponent } from './components/game-master-turntracker/game-master-turntracker.component';
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog/choose-monster-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -70,6 +73,8 @@ import { GameMasterShopkeepersTableComponent } from './components/game-master-sh
|
||||
GameMasterMonstersTableComponent,
|
||||
SpellDetailsDialogComponent,
|
||||
GameMasterShopkeepersTableComponent,
|
||||
GameMasterTurntrackerComponent,
|
||||
ChooseMonsterDialogComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
|
||||
@ -98,6 +103,7 @@ import { GameMasterShopkeepersTableComponent } from './components/game-master-sh
|
||||
MatSortModule,
|
||||
MatTooltipModule,
|
||||
MatRadioModule,
|
||||
DragDropModule,
|
||||
],
|
||||
providers: [
|
||||
UserService,
|
||||
@ -119,6 +125,8 @@ import { GameMasterShopkeepersTableComponent } from './components/game-master-sh
|
||||
ThrowPrimaryAbilityComponent,
|
||||
SpellDetailsDialogComponent,
|
||||
GameMasterShopkeepersTableComponent,
|
||||
GameMasterTurntrackerComponent,
|
||||
ChooseMonsterDialogComponent,
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
@ -0,0 +1,41 @@
|
||||
table {
|
||||
background-color: initial;
|
||||
}
|
||||
|
||||
mat-paginator {
|
||||
background-color: initial;
|
||||
color: white;
|
||||
}
|
||||
|
||||
::ng-deep .mat-select-arrow {
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
::ng-deep .mat-select-value {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.mat-sort-header-container {
|
||||
color: whitesmoke !important;
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
::ng-deep .mat-dialog-container {
|
||||
background-color: #4a5867;
|
||||
color: whitesmoke;
|
||||
box-shadow: 0 11px 15px -7px rgba(0, 0, 0, 0.2),
|
||||
0 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 5px 20px 4px #d8d8d8;
|
||||
}
|
||||
|
||||
::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background {
|
||||
background-color: #df7c0f;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<h1 mat-dialog-title>Choose Monsters</h1>
|
||||
|
||||
<div mat-dialog-content>
|
||||
<mat-form-field>
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Dragon" #input>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="mat-elevation-z8">
|
||||
<table mat-table [dataSource]="dataSource" matSort class="w-100">
|
||||
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef> Select Monsters
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-checkbox (click)="$event.stopPropagation()"
|
||||
(change)="$event ? selection.toggle(row) : null"
|
||||
[checked]="selection.isSelected(row)">
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
|
||||
<td mat-cell *matCellDef="let row"> {{row.name}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="armorClass">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Armor Class </th>
|
||||
<td mat-cell *matCellDef="let row"> {{row.armorClass}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="hitPoints">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Hit Points </th>
|
||||
<td mat-cell *matCellDef="let row"> {{row.hitPoints}} </td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<tr class="mat-row" *matNoDataRow>
|
||||
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="CloseDialog()">Close</button>
|
||||
<button mat-button (click)="AddMonsters()" cdkFocusInitial>Add monsters</button>
|
||||
</div>
|
@ -0,0 +1,67 @@
|
||||
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/MonsterViewModel';
|
||||
import { MonsterService } from '../../../services/monster.service';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { ErrorResponse } from '../../../types/ErrorResponse';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
|
||||
@Component({
|
||||
selector: 'app-choose-monster-dialog',
|
||||
templateUrl: './choose-monster-dialog.component.html',
|
||||
styleUrls: ['./choose-monster-dialog.component.css'],
|
||||
})
|
||||
export class ChooseMonsterDialogComponent implements OnInit {
|
||||
displayedColumns: string[] = ['select', 'name', 'armorClass', 'hitPoints'];
|
||||
dataSource: MatTableDataSource<MonsterViewModel>;
|
||||
selection = new SelectionModel<MonsterViewModel>(true, []);
|
||||
|
||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ChooseMonsterDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
private monsterService: MonsterService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.monsterService
|
||||
.GetAllMonsters()
|
||||
.pipe(first())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.dataSource = new MatTableDataSource(result);
|
||||
this.dataSource.sort = this.sort;
|
||||
this.dataSource.paginator = this.paginator;
|
||||
},
|
||||
(error: ErrorResponse | HttpErrorResponse) => {
|
||||
if (error instanceof HttpErrorResponse) {
|
||||
error = error.error as ErrorResponse;
|
||||
}
|
||||
console.error(error.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
AddMonsters() {
|
||||
this.dialogRef.close(this.selection.selected);
|
||||
}
|
||||
|
||||
CloseDialog() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
applyFilter(event: Event) {
|
||||
const filterValue = (event.target as HTMLInputElement).value;
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
|
||||
if (this.dataSource.paginator) {
|
||||
this.dataSource.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ import { AppState } from '../../store/models/app-state.model';
|
||||
import { Router } from '@angular/router';
|
||||
import { GameMasterMonstersTableComponent } from '../game-master-monsters-table/game-master-monsters-table.component';
|
||||
import { GameMasterShopkeepersTableComponent } from '../game-master-shopkeepers-table/game-master-shopkeepers-table.component';
|
||||
import { GameMasterTurntrackerComponent } from '../game-master-turntracker/game-master-turntracker.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-game-master-dashboard',
|
||||
@ -66,6 +67,12 @@ export class GameMasterDashboardComponent implements OnInit, OnDestroy {
|
||||
componentToDisplay: 'GameMasterMonstersTableComponent',
|
||||
expanded: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Turn Tracker',
|
||||
iconName: 'ra ra-crossed-axes',
|
||||
componentToDisplay: 'GameMasterTurntrackerComponent',
|
||||
expanded: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Shopkeepers',
|
||||
iconName: 'ra ra-wooden-sign',
|
||||
@ -152,6 +159,9 @@ export class GameMasterDashboardComponent implements OnInit, OnDestroy {
|
||||
case 'GameMasterShopkeepersTableComponent':
|
||||
this.middleComponentName = GameMasterShopkeepersTableComponent;
|
||||
break;
|
||||
case 'GameMasterTurntrackerComponent':
|
||||
this.middleComponentName = GameMasterTurntrackerComponent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
.turn-tracker-main {
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
.first {
|
||||
background-color: #df7c0f !important;
|
||||
}
|
||||
|
||||
.turn-tracker-main > div {
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
margin: 0 25px 25px 0;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.turn-tracker-main > div > h2 {
|
||||
color: whitesmoke;
|
||||
}
|
||||
.no-focus:focus {
|
||||
outline: none;
|
||||
}
|
||||
.turn-tracker-main > div > h2 > button {
|
||||
top: -7px;
|
||||
}
|
||||
.turn-tracker-list {
|
||||
border: solid 1px #3d4751;
|
||||
min-height: 81px;
|
||||
background: #606f80;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
.to-right {
|
||||
float: right;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.turn-tracker-box {
|
||||
padding: 20px 10px;
|
||||
border-bottom: solid 1px #3d4751 !important;
|
||||
color: whitesmoke;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
cursor: move;
|
||||
background: #606f80;
|
||||
font-size: 14px;
|
||||
s426128 marked this conversation as resolved
s426128
commented
tutaj brakuje za to tutaj brakuje za to
height: 81px;
by każdy box miał tą samą wielkość co tracker
|
||||
}
|
||||
.turn-tracker-box-name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cdk-drag-preview {
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
|
||||
0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.character-list {
|
||||
s426128 marked this conversation as resolved
s426128
commented
trzeba to zmienić na 100%, bez tego nie wyświetli się pełna lista postaci, widoczny będzię tylko jeden użytkownik, nawet jesli zalogowanych jest dwóch trzeba to zmienić na 100%, bez tego nie wyświetli się pełna lista postaci, widoczny będzię tylko jeden użytkownik, nawet jesli zalogowanych jest dwóch
|
||||
height: 81px;
|
||||
}
|
||||
.cdk-drag-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cdk-drag-animating {
|
||||
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.example-box:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
|
||||
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<div class="turn-tracker-main" cdkDropListGroup>
|
||||
<div>
|
||||
<h2>
|
||||
Turn Tracker
|
||||
<button class="no-focus" mat-icon-button (click)="AddMonster()">
|
||||
<mat-icon>add_circle_outline</mat-icon>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
cdkDropList
|
||||
[cdkDropListData]="turnTrackerList"
|
||||
class="turn-tracker-list"
|
||||
(cdkDropListDropped)="drop($event)">
|
||||
<div class="turn-tracker-box" *ngFor="let item of turnTrackerList;let first = first" [ngClass]="{first: first}" cdkDrag>
|
||||
<span class="turn-tracker-box-name">
|
||||
{{item.name}}
|
||||
</span>
|
||||
<button class="no-focus" mat-icon-button (click)="DeleteRow(item)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="no-focus to-right" mat-button (click)="NextTurn()">
|
||||
Next turn <mat-icon>fast_forward</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>
|
||||
Players characters list
|
||||
<button class="no-focus" mat-icon-button (click)="GetLoggedCharacters()">
|
||||
<mat-icon>autorenew</mat-icon>
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<div
|
||||
cdkDropList
|
||||
[cdkDropListData]="characterList"
|
||||
class="turn-tracker-list"
|
||||
(cdkDropListDropped)="drop($event)">
|
||||
<div class="turn-tracker-box character-list" *ngFor="let item of characterList" cdkDrag>
|
||||
<span class="turn-tracker-box-name">
|
||||
{{item.name}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,145 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import {
|
||||
CdkDragDrop,
|
||||
moveItemInArray,
|
||||
transferArrayItem,
|
||||
} from '@angular/cdk/drag-drop';
|
||||
import { CharacterService } from '../../../services/character.service';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { ChooseMonsterDialogComponent } from '../choose-monster-dialog/choose-monster-dialog.component';
|
||||
import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/MonsterViewModel';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AddTurnTrackerList } from '../../store/actions/game-master.actions';
|
||||
import { AppState } from '../../store/models/app-state.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-game-master-turntracker',
|
||||
templateUrl: './game-master-turntracker.component.html',
|
||||
styleUrls: ['./game-master-turntracker.component.css'],
|
||||
})
|
||||
export class GameMasterTurntrackerComponent implements OnInit, OnDestroy {
|
||||
turnTrackerList: {
|
||||
name: string;
|
||||
characterId: number;
|
||||
monsterId: number;
|
||||
}[] = [];
|
||||
|
||||
characterList: {
|
||||
name: string;
|
||||
characterId: number;
|
||||
monsterId: number;
|
||||
}[] = [];
|
||||
|
||||
drop(event: CdkDragDrop<any[]>) {
|
||||
if (event.previousContainer === event.container) {
|
||||
moveItemInArray(
|
||||
event.container.data,
|
||||
event.previousIndex,
|
||||
event.currentIndex
|
||||
);
|
||||
} else {
|
||||
transferArrayItem(
|
||||
event.previousContainer.data,
|
||||
event.container.data,
|
||||
event.previousIndex,
|
||||
s426128 marked this conversation as resolved
s426128
commented
tego przykładu chyba nie potrzebujemy? dziwnie wygląda wydanie tego do pokazu aplikacji tego przykładu chyba nie potrzebujemy? dziwnie wygląda wydanie tego do pokazu aplikacji
|
||||
event.currentIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
constructor(
|
||||
private characterService: CharacterService,
|
||||
public dialog: MatDialog,
|
||||
private store: Store<AppState>
|
||||
) {
|
||||
this.store
|
||||
.select((s) => s.gameMasterStore.turnTrackerList)
|
||||
.pipe(first())
|
||||
.subscribe((result) => {
|
||||
if (result.length > 0) {
|
||||
this.turnTrackerList = result;
|
||||
}
|
||||
this.GetLoggedCharacters();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
GetLoggedCharacters() {
|
||||
this.characterService
|
||||
.getLoggedCharacters()
|
||||
.pipe(first())
|
||||
.subscribe((result) => {
|
||||
const currentCharacterIds = this.turnTrackerList.map(
|
||||
(e) => e.characterId
|
||||
);
|
||||
this.characterList = result
|
||||
.filter((e) => !currentCharacterIds.includes(e.id))
|
||||
.map((e) => ({
|
||||
name: e.name,
|
||||
characterId: e.id,
|
||||
monsterId: null,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
DeleteRow(element: { name: string; characterId: number; monsterId: number }) {
|
||||
if (element.characterId != null) {
|
||||
this.turnTrackerList = this.turnTrackerList.filter(
|
||||
(e) => e.characterId !== element.characterId
|
||||
);
|
||||
} else {
|
||||
this.turnTrackerList = this.turnTrackerList.filter((e) => {
|
||||
return !(e.name == element.name && e.monsterId == element.monsterId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
NextTurn() {
|
||||
if (this.turnTrackerList.length > 1) {
|
||||
this.turnTrackerList = [
|
||||
...this.turnTrackerList.slice(1),
|
||||
this.turnTrackerList[0],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
AddMonster() {
|
||||
let dialogRef = this.dialog.open(ChooseMonsterDialogComponent, {
|
||||
width: '600px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result: MonsterViewModel[]) => {
|
||||
if (result != null) {
|
||||
let monstersOnList = this.turnTrackerList.filter(
|
||||
(c) => c.monsterId !== null
|
||||
);
|
||||
result.forEach((ele) => {
|
||||
if (monstersOnList.map((e) => e.name).includes(ele.name)) {
|
||||
debugger;
|
||||
let maxCurrentId = Math.max(
|
||||
...monstersOnList.map((e) => e.monsterId),
|
||||
0
|
||||
);
|
||||
maxCurrentId += 1;
|
||||
this.turnTrackerList = [
|
||||
...this.turnTrackerList,
|
||||
{ name: ele.name, characterId: null, monsterId: maxCurrentId },
|
||||
];
|
||||
} else {
|
||||
this.turnTrackerList = [
|
||||
...this.turnTrackerList,
|
||||
{ name: ele.name, characterId: null, monsterId: 1 },
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.store.dispatch(
|
||||
new AddTurnTrackerList({ turnTrackerList: this.turnTrackerList })
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
export enum GameMasterActionTypes {
|
||||
ADD_TURN_TRACKER_LIST = '[GAME MASTER] Add turn tracker list',
|
||||
}
|
||||
|
||||
export class AddTurnTrackerList implements Action {
|
||||
readonly type = GameMasterActionTypes.ADD_TURN_TRACKER_LIST;
|
||||
|
||||
constructor(
|
||||
public payload: {
|
||||
turnTrackerList: {
|
||||
name: string;
|
||||
characterId: number;
|
||||
monsterId: number;
|
||||
}[];
|
||||
}
|
||||
) {}
|
||||
}
|
||||
|
||||
export type GameMasterAction = AddTurnTrackerList;
|
@ -3,13 +3,17 @@ import {ActionReducerMap} from '@ngrx/store';
|
||||
import { AppReducer } from '../reducers/app.reducer';
|
||||
import { PlayerStoreModel } from './player-store.model';
|
||||
import { PlayerReducer } from '../reducers/player.reducer';
|
||||
import { GameMasterStoreModel } from './game-master-store.model';
|
||||
import { GameMasterReducer } from '../reducers/game-master.reducer';
|
||||
|
||||
export interface AppState {
|
||||
appStore: AppStoreModel;
|
||||
playerStore: PlayerStoreModel;
|
||||
gameMasterStore: GameMasterStoreModel;
|
||||
}
|
||||
|
||||
export const reducers: ActionReducerMap<AppState> = {
|
||||
appStore: AppReducer,
|
||||
playerStore: PlayerReducer,
|
||||
gameMasterStore: GameMasterReducer,
|
||||
};
|
||||
|
@ -0,0 +1,7 @@
|
||||
export interface GameMasterStoreModel {
|
||||
turnTrackerList: {
|
||||
name: string;
|
||||
characterId: number;
|
||||
monsterId: number;
|
||||
}[];
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { GameMasterStoreModel } from '../models/game-master-store.model';
|
||||
import {
|
||||
GameMasterAction,
|
||||
GameMasterActionTypes,
|
||||
} from '../actions/game-master.actions';
|
||||
|
||||
const initialState: GameMasterStoreModel = {
|
||||
turnTrackerList: [],
|
||||
};
|
||||
|
||||
export function GameMasterReducer(
|
||||
state: GameMasterStoreModel = initialState,
|
||||
action: GameMasterAction
|
||||
) {
|
||||
switch (action.type) {
|
||||
case GameMasterActionTypes.ADD_TURN_TRACKER_LIST:
|
||||
return { ...state, turnTrackerList: action.payload.turnTrackerList };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user
Choose Monsters : )