Skip to content

Commit

Permalink
#6: Auto-resolve invisible units and territories during replay, fixed…
Browse files Browse the repository at this point in the history
… visibility bug with edge between two visible territories
  • Loading branch information
tomwwright committed Nov 20, 2017
1 parent a70abdd commit 7ab97de
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/game/phaser/territory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default class TerritoryView {
}

onUpdateVisibility() {
this.spriteOverlay.alpha = this.gameStore.visibility.get(this.modelId) ? 0 : TERRITORY_VISIBILITY_OVERLAY_ALPHA;
this.spriteOverlay.alpha = this.gameStore.isLocationVisible(this.modelId) ? 0 : TERRITORY_VISIBILITY_OVERLAY_ALPHA;
}

onUpdateActionIndicator() {
Expand Down
12 changes: 1 addition & 11 deletions src/game/phaser/unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,7 @@ export default class UnitView {
onUpdateVisibility() {
const model = this.gameStore.map.unit(this.modelId);
if (model) {
const locationVisibility = this.gameStore.visibility.get(model.location.data.id);
this.spriteGroup.visible = locationVisibility;

// when in replay mode, units are visible if they occupy a visible location OR occupy a currently visible location NEXT turn
if (this.gameStore.isReplaying && model.data.destinationId) {
const futureModel = new GameMap(this.gameStore.game.data.maps[this.gameStore.turn]).unit(this.modelId);
if (futureModel) {
const futureLocationVisibility = this.gameStore.visibility.get(futureModel.location.data.id);
this.spriteGroup.visible = locationVisibility || futureLocationVisibility;
}
}
this.spriteGroup.visible = this.gameStore.isUnitVisible(this.modelId);
}
}

Expand Down
64 changes: 62 additions & 2 deletions src/game/stores/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { TerritoryModelAction } from 'models/actions/territory';
import { observable, action, computed } from 'mobx';
import PhaserStore from 'game/stores/phaser';
import GameProvider from 'game/providers/base';
import { ID, clone, contains, exclude } from 'models/utils';
import { ID, clone, contains, exclude, excludeAll } from 'models/utils';
import Game, { GameData } from 'models/game';
import GameMap, { GameMapData } from 'models/map';
import UnitContainer from 'models/unitcontainer';
Expand Down Expand Up @@ -73,9 +73,13 @@ export default class GameStore {
if (player) {
for (const territory of player.territories) {
visibility.set(territory.data.id, true);
territory.edges.map(edge => edge.data.id).forEach(id => visibility.set(id, true));
territory.edges.map(edge => edge.other(territory).data.id).forEach(id => visibility.set(id, true));
}
for (const edge of edges) {
if (visibility.get(edge.data.territoryAId) && visibility.get(edge.data.territoryBId)) {
visibility.set(edge.data.id, true);
}
}
for (const unit of player.units) {
visibility.set(unit.location.data.id, true);
}
Expand Down Expand Up @@ -303,21 +307,41 @@ export default class GameStore {

private toMovesState() {
this.resolveIds = this.map.units.filter(unit => unit.data.destinationId).map(unit => unit.data.id);

const invisibleResolveIds = this.resolveIds.filter(unitId => !this.isUnitVisible(unitId));
invisibleResolveIds.forEach(unitId => this.resolveMove(unitId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.MOVES;
}

private toEdgeMovesState() {
this.resolveIds = this.map.units.filter(unit => unit.data.destinationId && !unit.location.hasCombat()).map(unit => unit.data.id);

const invisibleResolveIds = this.resolveIds.filter(unitId => !this.isUnitVisible(unitId));
invisibleResolveIds.forEach(unitId => this.resolveMove(unitId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.EDGE_MOVES;
}

private toCombatsState() {
this.resolveIds = this.map.getCombats().map(combat => combat.location.data.id);

const invisibleResolveIds = this.resolveIds.filter(locationId => !this.isLocationVisible(locationId));
invisibleResolveIds.forEach(locationId => this.resolveCombat(locationId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.COMBATS;
}

private toAddDefendState() {
this.resolveIds = this.map.units.filter(unit => !contains(unit.data.statuses, Status.DEFEND)).map(unit => unit.data.id);

const invisibleResolveIds = this.resolveIds.filter(unitId => !this.isUnitVisible(unitId));
invisibleResolveIds.forEach(unitId => this.resolveAddDefend(unitId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.ADD_DEFEND;
}

Expand All @@ -328,16 +352,52 @@ export default class GameStore {

private toFoodState() {
this.resolveIds = clone(this.map.data.territoryIds);

const invisibleResolveIds = this.resolveIds.filter(territoryId => !this.isLocationVisible(territoryId));
invisibleResolveIds.forEach(territoryId => this.resolveFood(territoryId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.FOOD;
}

private toTerritoryControlState() {
this.resolveIds = clone(this.map.data.territoryIds);

const invisibleResolveIds = this.resolveIds.filter(territoryId => !this.isLocationVisible(territoryId));
invisibleResolveIds.forEach(territoryId => this.resolveTerritoryControl(territoryId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.TERRITORY_CONTROL;
}

private toTerritoryActionState() {
this.resolveIds = this.map.territories.filter(territory => territory.data.currentAction != null).map(territory => territory.data.id);

const invisibleResolveIds = this.resolveIds.filter(territoryId => !this.isLocationVisible(territoryId));
invisibleResolveIds.forEach(territoryId => this.resolveTerritoryAction(territoryId));
this.resolveIds = excludeAll(this.resolveIds, invisibleResolveIds);

this.resolveState = ResolveState.TERRITORY_ACTIONS;
}

public isUnitVisible(unitId: ID): boolean {
const model = this.map.unit(unitId);
const locationVisibility = this.visibility.get(model.location.data.id);
let visible = locationVisibility;

// when in replay mode, units are visible if they occupy a visible location OR occupy a currently visible location NEXT turn
if (this.isReplaying && model.data.destinationId) {
const futureModel = new GameMap(this.game.data.maps[this.turn]).unit(unitId);
if (futureModel) {
const futureLocationVisibility = this.visibility.get(futureModel.location.data.id);
visible = locationVisibility || futureLocationVisibility;
}
}

return visible;
}

public isLocationVisible(locationId): boolean {
return this.visibility.get(locationId);
}
}
2 changes: 1 addition & 1 deletion src/game/stores/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export default class UiStore {

@action
onClickNextPlayerGo() {
this.setTurn(Math.max(1, this.gameStore.turn - 1));
this.gameStore.setVisibility(VisibilityMode.CURRENT_PLAYER);
this.setTurn(Math.max(1, this.gameStore.turn - 1));
}

@action
Expand Down
15 changes: 14 additions & 1 deletion src/models/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { clone, sum, intersection, include, exclude, unique, clamp, collect, contains, flat } from "models/utils";
import { clone, sum, intersection, include, exclude, excludeAll, unique, clamp, collect, contains, flat } from "models/utils";
import { expect } from 'chai';
import { describe, it, beforeEach } from "mocha";

Expand Down Expand Up @@ -63,6 +63,19 @@ describe('Utils', () => {
expect(original).to.have.members([1, 2, 3]);
});

it('excludeAll', () => {
expect(excludeAll([1, 2, 3], [3, 3])).to.have.members([1, 2]);
expect(excludeAll([1, 2, 3], [2, 3])).to.have.members([1]);
expect(excludeAll([1, 2, 3, 2, 4], [2, 5])).to.have.members([1, 3, 4]);
expect(excludeAll([1, 2, 3], [5, 6])).to.have.members([1, 2, 3]);
expect(excludeAll([1, 2, null, 3], [2])).to.have.members([1, null, 3]);

const original = [1, 2, 3];
const excluded = excludeAll(original, [1, 2]);
expect(original).to.not.equal(excluded);
expect(original).to.have.members([1, 2, 3]);
});

it('unique', () => {
expect(unique([1, 2, 3, 4])).to.have.members([1, 2, 3, 4]);
expect(unique([1, 2, 2, 3, 3, 4])).to.have.members([1, 2, 3, 4]);
Expand Down
8 changes: 8 additions & 0 deletions src/models/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ export function exclude<T>(array: T[], thing: T): T[] {
return copy;
}

export function excludeAll<T>(array: T[], things: T[]): T[] {
const copy = [];
for (const a of array) {
if (!contains(things, a)) copy.push(a);
}
return copy;
}

export function flat<T>(arrays: (T | T[])[]): T[] {
const flattened: T[] = [];
const flatten = (elementOrArray: T | T[]) => {
Expand Down

0 comments on commit 7ab97de

Please sign in to comment.