Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add alternate timeline option #46

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions src/app/aliens/alien.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map, retry, shareReplay } from 'rxjs/operators';
import { Alien, GameSelection, SetupLevel, SetupType } from '../types';
import { Alien, AlienDescriptor, Game, GameSelection, SetupLevel, SetupType } from '../types';

@Injectable({ providedIn: 'root' })
export class AlienService {
/** Promise that returns once data is fetched */
public init$: Observable<string[]>;
/** Get alien from name */
public get: (name: string) => Alien;
public get: (name: string, games?: GameSelection) => Alien;
/** Get names that match given properties */
public getMatchingNames: (levels: boolean[], games: GameSelection, exclude?: string[], setup?: SetupLevel) => string[];

normalizeAlien: (alien: AlienDescriptor, games: GameSelection) => Alien;

public constructor(http: HttpClient) {
const aliens: Record<string, Alien> = {};
const aliens: Record<string, AlienDescriptor> = {};
const names: string[] = [];

this.init$ = http.get<Alien.Data>('data/aliens2.json').pipe(
Expand All @@ -30,15 +32,39 @@ export class AlienService {
shareReplay(),
);

this.get = name => aliens[name];
this.get = (name: string, games?: GameSelection) => {
return this.normalizeAlien(aliens[name], games || {});
};

this.getMatchingNames = (levels, games, exclude, setup) => names.filter(name => {
const alien = aliens[name];
// Normalize the alien based on the game selection
const alien = this.normalizeAlien(aliens[name], games);
// Matches level and game
return levels[alien.level] && games[alien.game] &&
return levels[alien.level] && (games[alien.game] || (games[Game.OdysseyAlternate] && alien.alternate)) &&
// No exclude by name, or not in exclude list
(!exclude || !exclude.length || exclude.indexOf(name) < 0) &&
// No setup restriction or no alien setup or (only restrict color and alien setup is not color)
(!setup || !alien.setup || (setup === SetupLevel.RequiresExtraColor && alien.setup !== SetupType.RequiresExtraColor));
});

this.normalizeAlien = (alien, games) => {
// Normalize the alien based on the game selection
const { powers, ...rest } = alien;
let normalized: Alien;
if(games[Game.OdysseyAlternate] && powers.length > 1) {
normalized = {
...rest,
...powers[1],
alternate: true,
};
} else {
normalized = {
...rest,
...powers[0],
};
}

return normalized;
};
}
}
4 changes: 2 additions & 2 deletions src/app/aliens/grid/grid.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</button>
</div>
<mat-card-title class="alien-fg">{{alien.name}}</mat-card-title>
<mat-card-subtitle>{{alien.power}}</mat-card-subtitle>
<mat-card-subtitle class="alien-power" [ngClass]="{ 'alien-alternate': alien.alternate }">{{alien.summary}}</mat-card-subtitle>
</mat-card-header>
<mat-card-footer>
<div class="bar alien-bg">
Expand All @@ -29,4 +29,4 @@
</div>
</mat-card-footer>
</mat-card>
</div>
</div>
6 changes: 3 additions & 3 deletions src/app/generator/page/page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const STORAGE_PREFIX = 'cosmic.alien-gen';
type Actions = 'draw' | 'hide' | 'show' | 'redo' | 'reset';

/** Generator settings */
interface ISettings {
export interface ISettings {
levels: boolean[];
games: GameSelection;
namesExcluded: string[];
Expand Down Expand Up @@ -97,7 +97,7 @@ export class AlienGeneratorPageComponent implements OnInit {

// if current choice has any restrictions, remove them from pool as well
if(preventConflicts) {
const alien = Aliens.get(name);
const alien = Aliens.get(name, this.settings.games);
if(alien.restriction) {
for(const restriction of alien.restriction.split(',')) {
const index = pool.indexOf(restriction);
Expand Down Expand Up @@ -262,7 +262,7 @@ export class AlienGeneratorPageComponent implements OnInit {
*/
private setState(aliens: string[], message: string, limit?: number) {
this.state = message;
this.aliensToShow = aliens.map(e => this.Aliens.get(e));
this.aliensToShow = aliens.map(e => this.Aliens.get(e, this.settings.games));
if(limit) { this.settings.numToChoose = limit; }
this.status = this.getStatus();
this.disabled = this.getDisabledActions(this.settings.numToChoose, this.aliensToShow.length);
Expand Down
11 changes: 9 additions & 2 deletions src/app/options/games/games.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
<mat-card-title>Games to include</mat-card-title>
<mat-list>
<mat-list-item *ngFor="let game of names">
<mat-checkbox class="mat-primary" (change)="select()" [(ngModel)]="games[game]">{{game}}</mat-checkbox>
<mat-checkbox
class="mat-primary"
[(ngModel)]="games[game]"
[disabled]="game === GameEnum.OdysseyAlternate && !games[GameEnum.Odyssey]"
(change)="select()"
>
{{game}}
</mat-checkbox>
</mat-list-item>
</mat-list>
</mat-card>
</mat-card>
10 changes: 9 additions & 1 deletion src/app/options/games/games.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ import { GameSelection, Game } from '../../types';
export class GameOptionsComponent {
@Output() public change = new EventEmitter<GameSelection>();
@Input() public games: GameSelection = {};
readonly GameEnum = Game;
public names: Game[] = [
Game.Encounter, Game.Alliance,
Game.Conflict, Game.Dominion,
Game.Eons, Game.Incursion,
Game.Storm, Game.Odyssey,
Game.OdysseyAlternate,
];

public select() { this.change.emit(this.games); }
public select() {
// Deselect the alternate timeline if Odyssey is not selected
if(!this.games[Game.Odyssey]) {
this.games[Game.OdysseyAlternate] = false;
}
this.change.emit(this.games);
}

}
2 changes: 1 addition & 1 deletion src/app/reference/page/page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ export class AlienReferencePageComponent implements OnInit {

/** Refresh shown aliens based on settings */
private refresh() {
this.groups = groupItems(this.Aliens.getMatchingNames(this.levels, this.games).map(this.Aliens.get), ['game', 'level'], ['name']);
this.groups = groupItems(this.Aliens.getMatchingNames(this.levels, this.games).map((value) => this.Aliens.get(value, this.games)), ['game', 'level'], ['name']);
}
}
22 changes: 13 additions & 9 deletions src/app/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** Game names */
export const enum Game {
export enum Game {
Encounter = 'Encounter',
Alliance = 'Alliance',
Conflict = 'Conflict',
Expand All @@ -8,6 +8,7 @@ export const enum Game {
Storm = 'Storm',
Eons = 'Eons',
Odyssey = 'Odyssey',
OdysseyAlternate = 'Odyssey (Alternate Timeline)',
}

/** What kind of setup to filter */
Expand Down Expand Up @@ -36,36 +37,39 @@ export const enum Requirement {
}

/** Details that I've transcribed for all aliens */
type BasicAlien = Readonly<{
export type AlienDescriptor = Readonly<{
name: string;
game: Game;
power: string;
level: 0 | 1 | 2;
description: string;
setup: SetupType;
powers: AlienPower[]
}>;

/** All details about an alien */
export type Alien = BasicAlien & Readonly<{
type AlienPower = Readonly<{
summary: string;
description: string;
setup: SetupType;
restriction?: string;
player?: string;
mandatory?: Requirement;
phases?: string;
alternate?: boolean;
}>;

export type Alien = Omit<AlienDescriptor, 'powers'> & AlienPower;

/** Whether games are selected */
export type GameSelection = Partial<Record<Game, boolean>>;

// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Alien {
/** Properties that all aliens have */
export type MandatoryProperties = (keyof BasicAlien)[];
export type MandatoryProperties = (keyof Omit<AlienDescriptor, 'powers'>)[];

/** Properties that I've only transcribed for some aliens */
export type Properties = (keyof Alien)[];

/** JSON format of alien data file */
export interface Data {
list: Alien[];
list: AlienDescriptor[];
}
}
3,309 changes: 3,308 additions & 1 deletion src/data/aliens2.json

Large diffs are not rendered by default.

10 changes: 1 addition & 9 deletions src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,9 @@ alien-grid {
}
.mat-card-title {
font-weight: bold;
margin: {
left: -$margin;
right: -$margin;
}
}
.mat-card-subtitle {
font-weight: normal;
margin: {
left: -$margin;
right: -$margin;
}
}
.mat-icon {
width: 2*$margin;
Expand Down Expand Up @@ -105,4 +97,4 @@ alien-grid {

@import './styles/home.scss';
@import './styles/generator.scss';
@import './styles/reference.scss';
@import './styles/reference.scss';
11 changes: 10 additions & 1 deletion src/styles/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,13 @@ $alien-2-theme: mat.define-light-theme($cosmic-primary, $alien-2-palette);
.alien-fg { color: $level2; }
@include mat.button-theme($alien-2-theme);
@include mat.checkbox-theme($alien-2-theme);
}
}
.alien-power {
padding: 4px;
border-radius: 4px;
margin-left: -4px;
}
.alien-alternate {
background-color: #333;
color: #fff;
}