...
 
Commits (25)
......@@ -73,6 +73,38 @@ export class PixiCellRenderer extends PixiInstructionRenderer {
director.animations.push(cursorAnim);
}
private static renderCorruption(instr: CellRenderInstruction, director: PixiRenderingDirector, container: PIXI.Container): void {
if (instr.cell.corruption > 0) {
let corruptX: number;
const corruptY: number = 8;
switch (instr.cell.corruption) {
case 1:
corruptX = 4;
break;
case 2:
corruptX = 5;
break;
default:
corruptX = 6;
}
const sr: SpriteReference = new SpriteReference(
SpriteSheetReference.small,
corruptX,
corruptY,
ColorHelper.getCorruptionColor(instr.cell.corruption, false),
0.5
);
const corruptSprite: PIXI.Sprite = PixiHelpers.buildSprite(director, sr, instr.size, '');
container.addChild(corruptSprite);
}
}
public render(director: PixiRenderingDirector, instr: CellRenderInstruction, container: PIXI.Container): void {
// Set up the tooltip now
if (instr.tooltip) {
......@@ -90,22 +122,33 @@ export class PixiCellRenderer extends PixiInstructionRenderer {
// Render floor
if (instr.cell.spriteReference) {
const sprite: PIXI.Sprite = PixiHelpers.buildSprite(
director,
instr.cell.spriteReference,
instr.size,
PixiCellRenderer.getEffectiveTint(instr.cell.spriteReference.tint, shouldShade)
);
let tint: string = PixiCellRenderer.getEffectiveTint(instr.cell.spriteReference.tint, shouldShade);
if (instr.visualizer) {
tint = instr.visualizer.getTint(instr, tint);
}
const sprite: PIXI.Sprite = PixiHelpers.buildSprite(director, instr.cell.spriteReference, instr.size, tint);
container.addChild(sprite);
}
// Render corruption, as needed
PixiCellRenderer.renderCorruption(instr, director, container);
// Render objects
for (const obj of instr.cell.objects.slice(0).sort((a: GameObject, b: GameObject): number => a.zIndex - b.zIndex)) {
let effectiveTint: string = obj.spriteReference.tint;
// Add corruption tint
if (obj.corruption > 0) {
effectiveTint = ColorHelper.getCorruptionColor(obj.corruption, false);
}
const sprite: PIXI.Sprite = PixiHelpers.buildSprite(
director,
obj.spriteReference,
instr.size,
PixiCellRenderer.getEffectiveTint(obj.spriteReference.tint, shouldShade)
PixiCellRenderer.getEffectiveTint(effectiveTint, shouldShade)
);
container.addChild(sprite);
......@@ -114,7 +157,14 @@ export class PixiCellRenderer extends PixiInstructionRenderer {
if (instr.cell.actor && instr.context.isVisible) {
const spriteRef: SpriteReference = instr.cell.actor.spriteReference;
const sprite: PIXI.Sprite = PixiHelpers.buildSprite(director, spriteRef, instr.size, instr.cell.actor.spriteReference.tint);
let effectiveTint: string = instr.cell.actor.spriteReference.tint;
// Add corruption tint
if (instr.cell.actor.corruption > 0) {
effectiveTint = ColorHelper.getCorruptionColor(instr.cell.actor.corruption, false);
}
const sprite: PIXI.Sprite = PixiHelpers.buildSprite(director, spriteRef, instr.size, effectiveTint);
container.addChild(sprite);
if (spriteRef.tint) {
......
......@@ -12,6 +12,7 @@ import { PixiCellRenderer } from './pixi-cell-renderer';
import { PixiInstructionRenderer } from './pixi-instruction-renderer';
import { PixiLogRenderer } from './pixi-log-renderer';
import { PixiRectangleRenderer } from './pixi-rectangle-renderer';
import { PixiSpriteFlashRenderer } from './pixi-sprite-flash-renderer';
import { PixiSpriteProjectileRenderer } from './pixi-sprite-projectile-renderer';
import { PixiTextCalloutRenderer } from './pixi-text-callout-renderer';
import { PixiTextRenderer } from './pixi-text-renderer';
......@@ -33,6 +34,7 @@ export class PixiInstructionRendererFactory implements IRendererProvider {
this.handlers['CellFlashInstruction'] = (): PixiInstructionRenderer => new PixiCellFlashRenderer();
this.handlers['TextCalloutInstruction'] = (): PixiInstructionRenderer => new PixiTextCalloutRenderer();
this.handlers['SpriteProjectileInstruction'] = (): PixiInstructionRenderer => new PixiSpriteProjectileRenderer();
this.handlers['SpriteFlashInstruction'] = (): PixiInstructionRenderer => new PixiSpriteFlashRenderer();
}
}
......
/*
* Copyright (c) 2018 Matt Eland
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import * as PIXI from 'pixi.js';
import { RenderInstruction } from '../../../libraries/rendering/render-instruction';
import { SpriteFlashInstruction } from '../../../libraries/rendering/sprite-flash-instruction';
import { FadeOutAnimation } from '../animation/fade-out-animation';
import { PixiHelpers } from './pixi-helpers';
import { PixiInstructionRenderer } from './pixi-instruction-renderer';
import { PixiRenderingDirector } from './pixi-rendering-director';
export class PixiSpriteFlashRenderer extends PixiInstructionRenderer {
public getContainer(director: PixiRenderingDirector, instr: RenderInstruction): PIXI.Container {
const container: PIXI.Container = new PIXI.Container();
director.addContainer(container, instr.renderingLayer);
return container;
}
public render(director: PixiRenderingDirector, instr: SpriteFlashInstruction, container: PIXI.Container): void {
const rect: PIXI.Graphics = new PIXI.Graphics();
container.addChild(rect);
container.position.set(instr.startPixel.x, instr.startPixel.y);
const sprite: PIXI.Sprite = PixiHelpers.buildSprite(director, instr.spriteRef, instr.size);
container.addChild(sprite);
director.animations.push(new FadeOutAnimation(sprite, instr.spriteFadeRate));
director.addAnimations(instr, rect, instr.bgColor);
}
}
......@@ -5,6 +5,7 @@
import * as chromatism from 'chromatism';
import { ColourModes, ColourObject } from 'chromatism';
import { MaterialColor } from './material-color.enum';
import RGB = ColourModes.RGB;
export class ColorHelper {
......@@ -84,4 +85,30 @@ export class ColorHelper {
return c.hex;
}
public static getCorruptionColor(corruption: number, isActor: boolean): string {
if (isActor) {
switch (corruption) {
case 3:
return MaterialColor.purpleLight1;
case 2:
return MaterialColor.purpleLight2;
case 1:
return MaterialColor.purpleLight3;
default:
return MaterialColor.white;
}
} else {
switch (corruption) {
case 3:
return MaterialColor.purpleDark3;
case 2:
return MaterialColor.purpleDark2;
case 1:
return MaterialColor.purpleDark1;
default:
return MaterialColor.white;
}
}
}
}
......@@ -112,5 +112,33 @@ export enum MaterialColor {
blueGreyDark3 = '#37474f',
blueGreyDark4 = '#263238',
purple = '#9c27b0'
pinkLight5 = '#fce4ec',
pinkLight4 = '#f8bbd0',
pinkLight3 = '#f48fb1',
pinkLight2 = '#f06292',
pinkLight1 = '#ec407a',
pink = '#e91e63',
pinkDark1 = '#d81b60',
pinkDark2 = '#c2185b',
pinkDark3 = '#ad1457',
pinkDark4 = '#880e4f',
pinkAccent1 = '#ff80ab',
pinkAccent2 = '#ff4081',
pinkAccent3 = '#f50057',
pinkAccent4 = '#c51162',
purpleLight5 = '#f3e5f5',
purpleLight4 = '#e1bee7',
purpleLight3 = '#ce93d8',
purpleLight2 = '#ba68c8',
purpleLight1 = '#ab47bc',
purple = '#9c27b0',
purpleDark1 = '#8e24aa',
purpleDark2 = '#7b1fa2',
purpleDark3 = '#6a1b9a',
purpleDark4 = '#4a148c',
purpleAccent1 = '#ea80fc',
purpleAccent2 = '#e040fb',
purpleAccent3 = '#d500f9',
purpleAccent4 = '#aa00ff'
}
......@@ -3,8 +3,9 @@
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import {Cell} from '../world/cell';
import {TooltipInfo} from './tooltip-info';
import { environment } from '../../../environments/environment';
import { Cell } from '../world/cell';
import { TooltipInfo } from './tooltip-info';
export class CellColorizer {
public getCellTooltip(cell: Cell, isDebugMode: boolean, isVisible: boolean): TooltipInfo {
......@@ -22,13 +23,26 @@ export class CellColorizer {
info.body = `\r\nUnallocated Space`;
}
if (isDebugMode) {
info.title += ` ${cell.pos.toString()}`;
if (cell.actor) {
info.footer = `${cell.actor.id}`;
// Add corruption tags
if (cell.corruption > 0) {
if (cell.corruption >= 3) {
info.body += `\r\nExtremely Corrupted`;
} else if (cell.corruption >= 2) {
info.body += `\r\nHeavily Corrupted`;
} else {
info.body += `\r\nMildly Corrupted`;
}
if (environment.allowDebugMode) {
info.body += ` (${cell.corruption})`;
}
}
// Add Debug info
if (environment.allowDebugMode) {
info.title += ` ${cell.pos.toString()}`;
}
info.renderThumbnail = true;
return info;
......
......@@ -3,6 +3,7 @@
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { VisualizerBase } from '../../services/visualizerBase';
import { MaterialColor } from '../material-color.enum';
import { Cell } from '../world/cell';
import { ICellInstructionGenerationContext } from './generation/i-cell-instruction-generation-context';
......@@ -13,6 +14,7 @@ export class CellRenderInstruction extends RenderInstruction {
public context: ICellInstructionGenerationContext;
public cell: Cell;
public cursorColor: MaterialColor;
public visualizer: VisualizerBase;
constructor(context: ICellInstructionGenerationContext, cell: Cell) {
super(context.screenPos, context.charSize);
......
......@@ -4,6 +4,7 @@
*/
import { IGameState } from '../../../services/core-engine/IGameState';
import { VisualizerBase } from '../../../services/visualizerBase';
import { Actor } from '../../world/actors/actor';
import { Point } from '../../world/point';
import { CellColorizer } from '../cell-colorizer';
......@@ -19,4 +20,5 @@ export interface ICellInstructionGenerationContext {
screenPos: Point;
charSize: Point;
state: IGameState;
visualizer: VisualizerBase;
}
/*
* Copyright (c) 2018 Matt Eland
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { IEffect } from '../../services/core-engine/IEffect';
import { MaterialColor } from '../material-color.enum';
import { Point } from '../world/point';
import { RenderInstruction } from './render-instruction';
import { RenderingLayer } from './rendering-layer.enum';
import { SpriteReference } from './sprite-reference';
export class SpriteFlashInstruction extends RenderInstruction {
private readonly _effect: IEffect;
private readonly _spriteRef: SpriteReference;
private readonly _spriteFadeRate: number;
constructor(screenPos: Point, size: Point, effect: IEffect, spriteRef: SpriteReference, spriteFadeRate: number) {
super(screenPos, size, MaterialColor.white);
this._effect = effect;
this._spriteRef = spriteRef;
this._spriteFadeRate = spriteFadeRate;
this.renderingLayer = RenderingLayer.level;
}
get effect(): IEffect {
return this._effect;
}
get spriteRef(): SpriteReference {
return this._spriteRef;
}
get spriteFadeRate(): number {
return this._spriteFadeRate;
}
}
......@@ -17,6 +17,7 @@ export class Actor {
public maxHp: number = 3;
public currentOps: number = 10;
public maxOps: number = 10;
public corruption: number;
public pos: Point = new Point(0, 0);
public id: string;
......
......@@ -44,20 +44,20 @@
{
"id": "ACTOR_ANTI_VIRUS",
"spriteSheet": "small",
"spriteX": 11,
"spriteX": 13,
"spriteY": 3
},
{
"id": "ACTOR_DAEMON",
"spriteSheet": "small",
"spriteX": 14,
"spriteY": 3
"spriteX": 11,
"spriteY": 6
},
{
"id": "ACTOR_DEFENDER",
"spriteSheet": "small",
"spriteX": 13,
"spriteY": 3
"spriteX": 11,
"spriteY": 5
},
{
"id": "ACTOR_INSPECTOR",
......@@ -74,8 +74,8 @@
{
"id": "ACTOR_GARBAGE_COLLECTOR",
"spriteSheet": "small",
"spriteX": 11,
"spriteY": 4
"spriteX": 9,
"spriteY": 6
},
{
"id": "ACTOR_BIT",
......@@ -101,6 +101,36 @@
"spriteX": 10,
"spriteY": 3
},
{
"id": "ACTOR_VIRUS",
"spriteSheet": "small",
"spriteX": 15,
"spriteY": 5
},
{
"id": "ACTOR_BUG",
"spriteSheet": "small",
"spriteX": 15,
"spriteY": 6
},
{
"id": "ACTOR_FEATURE",
"spriteSheet": "small",
"spriteX": 9,
"spriteY": 5
},
{
"id": "ACTOR_WORM",
"spriteSheet": "small",
"spriteX": 12,
"spriteY": 5
},
{
"id": "ACTOR_GLITCH",
"spriteSheet": "small",
"spriteX": 11,
"spriteY": 4
},
{
"id": "ACTOR_LOGIC_BOMB",
"spriteSheet": "small",
......
......@@ -4,6 +4,9 @@
*/
export enum GameCommand {
prevDebugView = 'PREV_DEBUG_VIEW',
nextDebugView = 'NEXT_DEBUG_VIEW',
toggleDebugView = 'TOGGLE_DEBUG',
internalCommand = 'INTERNAL_COMMAND',
showInventory = 'SHOW_INVENTORY',
cancel = 'CANCEL',
......
......@@ -17,6 +17,7 @@ export class Cell {
public terrainName: string;
public actor: Actor = null;
public pos: Point = new Point(0, 0);
public corruption: number;
constructor(cell: Cell = null) {
if (cell) {
......
......@@ -185,7 +185,7 @@ export class GameLevel {
this._height = this.maxY - this.minY;
}
public addCell(floorType: FloorType, pos: Point): void {
public addCell(floorType: FloorType, pos: Point): Cell {
// Ensure the row exists
if (!this.rows[pos.y]) {
this.rows[pos.y] = new CellRow();
......@@ -199,5 +199,7 @@ export class GameLevel {
// Add the new object to the data
this.rows[pos.y].cells[pos.x] = cellObj;
return cellObj;
}
}
......@@ -4,6 +4,7 @@
*/
import { IObjectData } from '../../../services/generation-service/i-object-data';
import { Logger } from '../../../shared/utility/logger';
import { SpriteReference } from '../../rendering/sprite-reference';
import { SpriteSheetReference } from '../../rendering/sprite-sheet-reference.enum';
import { GameLevel } from '../game-level';
......@@ -18,6 +19,8 @@ export class CommandPickup extends Pickup {
constructor(level: GameLevel, data: IObjectData) {
super(level, data);
Logger.warn(`Creating Command Pickup`, data);
this.command = data.id;
}
......
......@@ -23,6 +23,7 @@ export abstract class GameObject {
this.data = data;
this.level = level;
}
get name(): string {
......@@ -44,4 +45,8 @@ export abstract class GameObject {
get backgroundColor(): string {
return undefined;
}
get corruption(): number {
return this.data.corruption;
}
}
/*
* Copyright (c) 2018 Matt Eland
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { IObjectData } from '../../../services/generation-service/i-object-data';
import { Logger } from '../../../shared/utility/logger';
import { SpriteReference } from '../../rendering/sprite-reference';
import { SpriteSheetReference } from '../../rendering/sprite-sheet-reference.enum';
import { GameLevel } from '../game-level';
import { Pickup } from './pickup';
export class GenericPickup extends Pickup {
public command: string;
private readonly spriteRef: SpriteReference;
constructor(level: GameLevel, data: IObjectData) {
super(level, data);
Logger.warn(`Creating Generic Pickup`, data);
switch (data.id) {
case 'GET_HP':
this.spriteRef = new SpriteReference(SpriteSheetReference.small, 6, 5);
break;
case 'GET_OPS':
this.spriteRef = new SpriteReference(SpriteSheetReference.small, 3, 5);
break;
case 'GET_MAXHP':
this.spriteRef = new SpriteReference(SpriteSheetReference.small, 6, 3);
break;
case 'GET_MAXOPS':
this.spriteRef = new SpriteReference(SpriteSheetReference.small, 5, 3);
break;
default:
this.spriteRef = new SpriteReference(SpriteSheetReference.small, 6, 0);
}
}
get spriteReference(): SpriteReference {
return this.spriteRef;
}
}
......@@ -5,7 +5,6 @@
import { Alignment } from '../../../services/generation-service/alignment.enum';
import { IActorData } from '../../../services/generation-service/i-actor-data';
import { Logger } from '../../../shared/utility/logger';
import { MaterialColor } from '../../material-color.enum';
import { SpriteReference } from '../../rendering/sprite-reference';
import { SpriteSheetReference } from '../../rendering/sprite-sheet-reference.enum';
......@@ -18,18 +17,24 @@ export class OperatingSystemCore extends GameObject {
constructor(level: GameLevel, data: IActorData) {
super(level, data);
Logger.debug(`Adding OS Core. Team: ${data.team}`);
this.isCaptured = data.team === Alignment.Player;
}
get spriteReference(): SpriteReference {
return this.isCaptured ? new SpriteReference(SpriteSheetReference.small, 0, 4) : new SpriteReference(SpriteSheetReference.small, 1, 4);
if (this.data.team === Alignment.Player) {
return new SpriteReference(SpriteSheetReference.small, 0, 4);
} else if (this.data.team === Alignment.Virus || this.data.team === Alignment.Bug) {
return new SpriteReference(SpriteSheetReference.small, 2, 4);
} else {
return new SpriteReference(SpriteSheetReference.small, 1, 4);
}
}
get foregroundColor(): string {
if (this.isCaptured) {
if (this.data.team === Alignment.Player) {
return MaterialColor.greenAccent2;
} else if (this.data.team === Alignment.Virus || this.data.team === Alignment.Bug) {
return MaterialColor.purple;
} else {
return MaterialColor.red;
}
......
......@@ -16,7 +16,7 @@ export class ServiceObject extends GameObject {
constructor(level: GameLevel, data: IObjectData) {
super(level, data);
this.isActive = false;
this.isActive = data.state === 'ACTIVE';
}
get foregroundColor(): string {
......@@ -28,6 +28,8 @@ export class ServiceObject extends GameObject {
}
get spriteReference(): SpriteReference {
return this.isActive ? new SpriteReference(SpriteSheetReference.small, 4, 5) : new SpriteReference(SpriteSheetReference.small, 6, 5);
return this.corruption > 0
? new SpriteReference(SpriteSheetReference.small, 8, 0)
: new SpriteReference(SpriteSheetReference.small, 7, 0);
}
}
......@@ -11,4 +11,5 @@ export interface IEffect {
startPos: string;
endPos: string;
text: string;
data: string;
}
......@@ -6,6 +6,7 @@
import { ILevel } from '../generation-service/i-level';
export interface IGameState {
uid: string;
level: ILevel;
/// <summary>
......
......@@ -9,7 +9,7 @@ export enum EffectType {
Destroyed,
Missed,
StabilityRestore,
OpsRestore,
OpsChanged,
Projectile,
Explosion,
Teleport,
......@@ -21,5 +21,7 @@ export enum EffectType {
PlayerTaunt,
SysTaunt,
VirusTaunt,
SysSecTaunt
SysSecTaunt,
Spawn,
Cleanse
}
......@@ -142,7 +142,7 @@ export class GameLoopService implements IInitializable {
private checkForGameOver(): GameOverInfo {
const state: IGameState = this.worldService.gameState;
if (state.isGameOver) {
if (state && state.isGameOver) {
const info: GameOverInfo = new GameOverInfo();
info.turnsTaken = state.numMoves;
info.damageDealt = state.totalDamageDealt;
......
......@@ -5,6 +5,7 @@
import { EventEmitter, Injectable } from '@angular/core';
import { Observable } from 'rxjs/observable';
import { isNullOrUndefined } from 'util';
import { environment } from '../../../environments/environment';
import { ActorCommand } from '../../libraries/world/actors/commands/actor-command';
import { CommandSlot } from '../../libraries/world/actors/commands/command-slot';
......@@ -32,6 +33,7 @@ export class GameService {
public readonly isProcessingCommandChanged: EventEmitter<boolean>;
private useSignalR: boolean = true;
private useServerState: boolean = true;
constructor(private httpService: HttpService, private signalRService: SignalRService, private messageService: MessageService) {
this.gameStateChanged = new EventEmitter<IGameState>();
......@@ -39,6 +41,7 @@ export class GameService {
this.isProcessingCommandChanged = new EventEmitter<boolean>();
this.useSignalR = environment.useSignalR;
this.useServerState = environment.useServerState;
}
private state: IGameState;
......@@ -140,25 +143,48 @@ export class GameService {
let observable: Observable<any>;
if (this.useSignalR) {
observable = this.signalRService.send('ProcessMove', parameters);
if (this.useServerState) {
if (this.useSignalR) {
observable = this.signalRService.send('ProcessCommand', parameters.state.uid, parameters.command);
} else {
observable = this.httpService.put(`api/game/${parameters.state.uid}`, parameters.command);
}
} else {
observable = this.httpService.put('api/game', parameters);
if (this.useSignalR) {
observable = this.signalRService.send('ProcessMove', parameters);
} else {
observable = this.httpService.put('api/game', parameters);
}
}
observable.subscribe(
(data: IGameResponse) => {
this.handleGameResponse(data);
// If the response was null, it could be because we are in SignalR / Server State Caching mode and the cached state was missing
// In this case, we'll just need to send the full state again
if (isNullOrUndefined(data) && this.useServerState && this.useSignalR) {
this.useServerState = false;
this.executeCommandAndHandleResponse(parameters);
} else {
this.handleGameResponse(data);
}
},
(err: any) => {
Logger.error(`Error executing move. PUT to api/game returned an error result`, err, parameters);
this.useSignalR = false; // Flip SignalR off in case it was the culprit
this.messageService.showMessage({
messageType: ClientMessageType.Assertion,
message: `Oops! There was a problem responding to your action. We'll get it fixed, but for now, try a different action.`
});
this.isProcessingCommand = false;
this.gameStateChanged.emit(this.state);
Logger.debug('Oh snapple', err);
if (err && err.status && +err.status === 404 && this.useServerState) {
this.useServerState = false;
Logger.warn('Server cached state for the current session was not found. Retrying with full state');
this.executeCommandAndHandleResponse(parameters);
} else {
Logger.error(`Error executing move. PUT to api/game returned an error result`, err, parameters);
this.useSignalR = false; // Flip SignalR off in case it was the culprit
this.messageService.showMessage({
messageType: ClientMessageType.Assertion,
message: `Oops! There was a problem responding to your action. We'll get it fixed, but for now, try a different action.`
});
this.isProcessingCommand = false;
this.gameStateChanged.emit(this.state);
}
}
);
}
......@@ -179,6 +205,9 @@ export class GameService {
this.effectsLoaded.emit(data.effects);
this.gameStateChanged.emit(data.state);
// Reset our communication preferences back to their server-defaults
this.useServerState = environment.useServerState;
} else {
Logger.warn(`Response did not contain any state`);
......
......@@ -86,7 +86,7 @@ export class WorldService implements IContextComponent {
this.bestiaryService.initialize();
// Use our level JSON to load the level
LevelGenerationService.addCells(level, levelData.cells, Point.fromPos2D(levelData.upperLeft));
LevelGenerationService.addCells(level, levelData, Point.fromPos2D(levelData.upperLeft));
this.levelGenerator.addObjects(level, levelData);
// Ensure our local representation of the player has the correct position
......
/*
* Copyright (c) 2018 Matt Eland
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { ColorHelper } from '../libraries/color-helper';
import { CellRenderInstruction } from '../libraries/rendering/cell-render-instruction';
import { VisualizerBase } from './visualizerBase';
export class CorruptionVisualizer extends VisualizerBase {
public getTint(instr: CellRenderInstruction, fallback: string): string {
return ColorHelper.getCorruptionColor(instr.cell.corruption, false);
}
}
......@@ -48,8 +48,11 @@ export class BestiaryService implements IInitializable, IContextComponent {
actor = new Actor(obj.id);
}
actor.corruption = obj.corruption;
actor.pos = Point.fromPos2D(obj.pos);
// Copy over properties
actor.name = obj.name;
actor.currentHp = obj.maxHP;
actor.maxHp = obj.maxHP;
if (obj.hpUsed) {
......
......@@ -3,13 +3,11 @@
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { Alignment } from './alignment.enum';
import { IObjectData } from './i-object-data';
export interface IActorData extends IObjectData {
opUsed: number;
maxOP: number;
team: Alignment;
visible: string[];
known: string[];
}
......@@ -14,6 +14,7 @@ export interface ILevel {
upperLeft: string;
lowerRight: string;
cells: string[];
corruption: string[];
objects: IObjectData[];
walls: IObjectData[];
actors: IActorData[];
......
......@@ -3,13 +3,17 @@
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { Alignment } from './alignment.enum';
import { ObjectType } from './object-type.enum';
export interface IObjectData {
corruption: number;
isHidden: boolean;
name: string;
type: ObjectType;
id: string;
team: Alignment;
hpUsed: number;
maxHP: number;
pos: string;
......
......@@ -8,6 +8,7 @@ import { isNullOrUndefined } from 'util';
import { Actor } from '../../libraries/world/actors/actor';
import { IActorDefinition } from '../../libraries/world/actors/i-actor-definition';
import { PlayerActor } from '../../libraries/world/actors/player-actor';
import { Cell } from '../../libraries/world/cell';
import { GameLevel } from '../../libraries/world/game-level';
import { Cabling } from '../../libraries/world/objects/cabling';
import { CharacterSelectTile } from '../../libraries/world/objects/character-select-tile';
......@@ -17,6 +18,7 @@ import { Divider } from '../../libraries/world/objects/divider';
import { Door } from '../../libraries/world/objects/door';
import { Firewall } from '../../libraries/world/objects/firewall';
import { GameObject } from '../../libraries/world/objects/game-object';
import { GenericPickup } from '../../libraries/world/objects/generic-pickup';
import { HelpTile } from '../../libraries/world/objects/help-tile';
import { Metadata } from '../../libraries/world/objects/metadata';
import { NetworkPort } from '../../libraries/world/objects/network-port';
......@@ -49,18 +51,21 @@ export class LevelGenerationService {
private actorDefinitionService: ActorDefinitionService
) {}
public static addCells(level: GameLevel, rows: string[], upperLeft: Point): void {
public static addCells(level: GameLevel, levelData: ILevel, upperLeft: Point): void {
let y: number = upperLeft.y;
let x: number;
let xIndex: number;
let yIndex: number = 0;
for (const row of rows) {
for (const row of levelData.cells) {
x = upperLeft.x;
xIndex = 0;
for (const cell of row) {
for (const c of row) {
const pos: Point = new Point(x, y);
let floorType: FloorType = FloorType.Void;
switch (cell) {
switch (c) {
case ' ':
floorType = FloorType.Void;
break;
......@@ -77,12 +82,16 @@ export class LevelGenerationService {
floorType = FloorType.Normal;
}
level.addCell(floorType, pos);
const cell: Cell = level.addCell(floorType, pos);
cell.corruption = +levelData.corruption[yIndex][xIndex];
x++;
xIndex++;
}
y++;
yIndex++;
}
}
......@@ -147,9 +156,12 @@ export class LevelGenerationService {
case ObjectType.Firewall:
gameObj = new Firewall(level, levelData.hasAdminAccess, obj);
break;
case ObjectType.Loot:
case ObjectType.CommandPickup:
gameObj = new CommandPickup(level, obj);
break;
case ObjectType.GenericPickup:
gameObj = new GenericPickup(level, obj);
break;
case ObjectType.Help:
gameObj = new HelpTile(level, obj);
break;
......
......@@ -55,7 +55,7 @@ export enum ObjectType {
/// <summary>
/// Freestanding loot to be collected
/// </summary>
Loot = 12,
CommandPickup = 12,
/// <summary>
/// A treasure chest
/// </summary>
......@@ -73,5 +73,6 @@ export enum ObjectType {
/// </summary>
Player = 16,
Help = 17,
CharacterSelect = 18
CharacterSelect = 18,
GenericPickup = 19
}
......@@ -20,6 +20,7 @@ import { LogRenderInstruction } from '../../libraries/rendering/log-render-instr
import { ProgressBarRenderInstruction } from '../../libraries/rendering/progress-bar-render-instruction';
import { RectangleInstruction } from '../../libraries/rendering/rectangle-instruction';
import { RenderInstruction } from '../../libraries/rendering/render-instruction';
import { SpriteFlashInstruction } from '../../libraries/rendering/sprite-flash-instruction';
import { SpriteProjectileInstruction } from '../../libraries/rendering/sprite-projectile-instruction';
import { SpriteReference } from '../../libraries/rendering/sprite-reference';
import { SpriteSheetReference } from '../../libraries/rendering/sprite-sheet-reference.enum';
......@@ -116,6 +117,7 @@ export class RenderInstructionGenerationService implements ITooltipProvider {
isInitialRender: this.context.isInitialRender,
isVisible: this.worldService.isCellVisible(pos),
isKnown: this.worldService.isCellKnown(pos),
visualizer: this.renderingService.currentVisualizer,
charSize: this.context.charSize,
actor: this.worldService.player,
state: this.worldService.gameState
......@@ -178,6 +180,7 @@ export class RenderInstructionGenerationService implements ITooltipProvider {
// This guy is going to do all of the heavy lifting
const instr: CellRenderInstruction = new CellRenderInstruction(context, cell);
instr.tooltip = context.colorizer.getCellTooltip(cell, context.isDebugMode, context.isVisible);
instr.visualizer = context.visualizer;
if (this.gameLoopService.gameState === GameStatus.selectingTarget) {
instr.clickFunction = (): boolean => this.commandService.specifyTargetForCommand(cell);
......@@ -456,6 +459,8 @@ export class RenderInstructionGenerationService implements ITooltipProvider {
effect.effect = EffectType.Damage;
}
let spriteRef: SpriteReference;
switch (effect.effect) {
case EffectType.ActivationEnd:
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.orangeAccent4, 20, 0.5));
......@@ -467,15 +472,16 @@ export class RenderInstructionGenerationService implements ITooltipProvider {
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.yellow, 24, 0.5));
break;
case EffectType.CellMarked:
this.instructions.push(new CellFlashInstruction(startScreenPos, cellSize, effect, MaterialColor.blueDark2));
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.blueAccent2, 24, 0.5));
spriteRef = new SpriteReference(SpriteSheetReference.small, 6, 7, '', 0.65);
this.instructions.push(new SpriteFlashInstruction(startScreenPos, cellSize, effect, spriteRef, 3));
break;
case EffectType.Damage:
this.instructions.push(new CellFlashInstruction(startScreenPos, cellSize, effect, MaterialColor.redDark4));
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.red, 24, 1));
break;
case EffectType.Destroyed:
// this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.redDark2, 12, 0.5));
spriteRef = new SpriteReference(SpriteSheetReference.small, 10, 6, '', 0.5);
this.instructions.push(new SpriteFlashInstruction(startScreenPos, cellSize, effect, spriteRef, 2));
break;
case EffectType.Explosion:
this.instructions.push(new CellFlashInstruction(startScreenPos, cellSize, effect, MaterialColor.redDark4));
......@@ -486,22 +492,41 @@ export class RenderInstructionGenerationService implements ITooltipProvider {
case EffectType.NoDamage:
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.white, 16, 0.5));
break;
case EffectType.OpsRestore:
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.orange, 16, 0.5));
case EffectType.OpsChanged:
let opsColor: string = MaterialColor.orange;
if (effect.data && +effect.data < 0) {
opsColor = MaterialColor.deepOrange;
}
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, opsColor, 16, 0.5));
break;
case EffectType.Projectile:
const spriteRef: SpriteReference = new SpriteReference(SpriteSheetReference.small, 2, 5, '', 0.65);
spriteRef = new SpriteReference(SpriteSheetReference.small, 3, 7, '', 0.65);
this.instructions.push(
new SpriteProjectileInstruction(startScreenPos, cellSize, effect, endScreenPos, spriteRef, MaterialColor.yellow)
new SpriteProjectileInstruction(startScreenPos, cellSize, effect, endScreenPos, spriteRef, MaterialColor.white)
);
break;
case EffectType.StabilityRestore:
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.green, 16, 0.5));
break;
case EffectType.Teleport:
this.instructions.push(new CellFlashInstruction(startScreenPos, cellSize, effect, MaterialColor.blueAccent2));
this.instructions.push(new CellFlashInstruction(endScreenPos, cellSize, effect, MaterialColor.blueAccent2));
spriteRef = new SpriteReference(SpriteSheetReference.small, 5, 6, '', 0.5);
this.instructions.push(new SpriteFlashInstruction(startScreenPos, cellSize, effect, spriteRef, 1));
spriteRef = new SpriteReference(SpriteSheetReference.small, 4, 6, '', 0.5);
this.instructions.push(new SpriteFlashInstruction(endScreenPos, cellSize, effect, spriteRef, 2));
break;
case EffectType.Spawn:
spriteRef = new SpriteReference(SpriteSheetReference.small, 4, 6, '', 0.5);
this.instructions.push(new SpriteFlashInstruction(startScreenPos, cellSize, effect, spriteRef, 2));
break;
case EffectType.Cleanse:
spriteRef = new SpriteReference(SpriteSheetReference.small, 5, 6, '', 0.5);
this.instructions.push(new SpriteFlashInstruction(startScreenPos, cellSize, effect, spriteRef, 2));
break;
case EffectType.HelpText:
this.instructions.push(new TextCalloutInstruction(startScreenPos, cellSize, effect, MaterialColor.blueAccent4, 20, 0.01));
break;
......
......@@ -4,18 +4,32 @@
*/
import { EventEmitter, Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import { Point } from '../../libraries/world/point';
import { Logger } from '../../shared/utility/logger';
import { WorldService } from '../core-engine/world.service';
import { CorruptionVisualizer } from '../corruptionVisualizer';
import { VisualizerBase } from '../visualizerBase';
@Injectable()
export class RenderingService {
public renderInvalidated: EventEmitter<boolean>;
public visualizerChanged: EventEmitter<VisualizerBase>;
private _zoomLevel: number = 2;
private readonly _debugViews: VisualizerBase[];
private _debugViewIndex: number;
private _visualizerEnabled: boolean;
constructor(private worldService: WorldService) {
this.renderInvalidated = new EventEmitter<boolean>();
this._debugViews = [new CorruptionVisualizer(), null];
this._debugViewIndex = 0;
this._visualizerEnabled = false;
this.visualizerChanged = new EventEmitter<VisualizerBase>();
}
get zoomLevel(): number {
......@@ -49,4 +63,50 @@ export class RenderingService {
public zoomOut(): void {
this.zoomLevel = Math.max(0.5, this.zoomLevel - 0.5);
}
public get currentVisualizer(): VisualizerBase {
if (!this._visualizerEnabled) {
return null;
}
return this._debugViews[this._debugViewIndex];
}
public nextDebugView(): void {
if (!environment.allowDebugMode) {
return;
}
if (++this._debugViewIndex >= this._debugViews.length) {
this._debugViewIndex = 0;
}
this._visualizerEnabled = true;
this.visualizerChanged.emit(this.currentVisualizer);
this.renderInvalidated.emit(false);
}
public prevDebugView(): void {
if (!environment.allowDebugMode) {
return;
}
if (--this._debugViewIndex < 0) {
this._debugViewIndex = this._debugViews.length - 1;
}
this._visualizerEnabled = true;
this.visualizerChanged.emit(this.currentVisualizer);
this.renderInvalidated.emit(false);
}
public toggleDebugView(): void {
if (!environment.allowDebugMode) {
return;
}
this._visualizerEnabled = !this._visualizerEnabled;
this.visualizerChanged.emit(this.currentVisualizer);
this.renderInvalidated.emit(false);
}
}
/*
* Copyright (c) 2018 Matt Eland
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { Injectable } from '@angular/core';
import * as signalR from '@aspnet/signalr';
import { HubConnection } from '@aspnet/signalr';
......@@ -13,12 +18,12 @@ export class SignalRService {
constructor() {}
public send(methodName: string, data: any): Observable<any> {
public send(methodName: string, ...data: any[]): Observable<any> {
return Observable.create((obs: Observer<any>) => {
if (!this._connection) {
this.connect().subscribe(() => this.sendToObservable(methodName, data, obs), (err: any) => obs.error(err));
this.connect().subscribe(() => this.sendToObservable(methodName, obs, ...data), (err: any) => obs.error(err));
} else {
this.sendToObservable(methodName, data, obs);
this.sendToObservable(methodName, obs, ...data);
}
});
}
......@@ -56,12 +61,12 @@ export class SignalRService {
});
}
private sendToObservable(methodName: string, data: any, obs: Observer<any>): void {
Logger.debug(`Sending SignalR Message '${methodName}'`, data);
private sendToObservable(methodName: string, obs: Observer<any>, ...data: any[]): void {
Logger.debug(`Sending SignalR Message '${methodName}'`, ...data);
// Do the invoke and chain the output to the observable we're subscribed to
this._connection
.invoke(methodName, data)
.invoke(methodName, ...data)
.then((r: any) => {
Logger.info(`SignalR invoke '${methodName}' succeeded`, r);
obs.next(r);
......
......@@ -83,6 +83,9 @@ export class InputService {
this._handlers[GameCommand.zoomIn] = (): void => this.renderingService.zoomIn();
this._handlers[GameCommand.zoomOut] = (): void => this.renderingService.zoomOut();
this._handlers[GameCommand.showInventory] = (): void => this.dialogService.showCharacterManagementScreen();
this._handlers[GameCommand.toggleDebugView] = (): void => this.renderingService.toggleDebugView();
this._handlers[GameCommand.nextDebugView] = (): void => this.renderingService.nextDebugView();
this._handlers[GameCommand.prevDebugView] = (): void => this.renderingService.prevDebugView();
// this._handlers['HELP'] = (): void => this.gameService.showHelpScreen();
}
......@@ -108,6 +111,7 @@ export class InputService {
this._keyCommandMap[68] = 'E'; // D
this._keyCommandMap[73] = GameCommand.showInventory;
this._keyCommandMap[83] = 'S'; // S
this._keyCommandMap[86] = GameCommand.toggleDebugView; // V
this._keyCommandMap[87] = 'N'; // W
this._keyCommandMap[98] = 'S'; // Numpad 2 with Numlock
this._keyCommandMap[100] = 'W'; // Numpad 4 with Numlock
......@@ -120,6 +124,8 @@ export class InputService {
this._keyCommandMap[189] = GameCommand.zoomOut; // -
this._keyCommandMap[187] = GameCommand.zoomIn; // +
this._keyCommandMap[219] = GameCommand.prevDebugView; // [
this._keyCommandMap[221] = GameCommand.nextDebugView; // ]
}
private buildMoveCommand(direction: any, commandType: CommandType): void {
......
......@@ -5,6 +5,7 @@
import { EventEmitter, Injectable } from '@angular/core';
import { CommandContext } from '../../libraries/world/actors/commands/command-context';
import { Logger } from '../../shared/utility/logger';
import { ClientMessageType } from '../core-engine/client-message-type.enum';
import { CommandContextService } from '../core-engine/command-context.service';
import { IClientMessage } from '../core-engine/i-client-message';
......@@ -49,6 +50,10 @@ export class MessageService implements IInitializable, IContextComponent {
public showMessage(message: IClientMessage): void {
if (message) {
if (!message || !message.message) {
Logger.warn(`Probable empty message encountered`, message);
}
this._logMessages.push(message);
this.messagesChanged.emit(this._logMessages);
}
......
/*
* Copyright (c) 2018 Matt Eland
* Licensed under the Eclipse Public License. See LICENSE file in the project root for full license information.
*/
import { CellRenderInstruction } from '../libraries/rendering/cell-render-instruction';
export abstract class VisualizerBase {
public abstract getTint(instr: CellRenderInstruction, fallback: string): string;
}
src/assets/Sprites3.png

5.63 KB | W: | H:

src/assets/Sprites3.png

8.36 KB | W: | H:

src/assets/Sprites3.png
src/assets/Sprites3.png
src/assets/Sprites3.png
src/assets/Sprites3.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -13,5 +13,6 @@ export const environment: any = {
version: 'Test Version',
traceAngularRoutes: false,
baseUrl: 'http://emergenceapidev.azurewebsites.net',
useServerState: true,
useSignalR: false
};
......@@ -13,5 +13,6 @@ export const environment: any = {
version: 'v{BUILD_VERSION}',
traceAngularRoutes: false,
baseUrl: 'https://emergenceapi.azurewebsites.net',
useServerState: true,
useSignalR: true
};
......@@ -13,5 +13,6 @@ export const environment: any = {
version: 'v{BUILD_VERSION} (Preview)',
traceAngularRoutes: true,
baseUrl: 'https://emergenceapi-preview.azurewebsites.net',
useServerState: true,
useSignalR: true
};
......@@ -13,5 +13,6 @@ export const environment: any = {
version: 'v{BUILD_VERSION} (Nightly)',
traceAngularRoutes: true,
baseUrl: 'https://emergenceapi-preview.azurewebsites.net',
useServerState: true,
useSignalR: true
};
......@@ -13,5 +13,6 @@ export const environment: any = {
version: 'v{BUILD_VERSION} (Preview)',
traceAngularRoutes: false,
baseUrl: 'https://emergenceapi-preview.azurewebsites.net',
useServerState: true,
useSignalR: true
};
......@@ -13,5 +13,6 @@ export const environment: any = {
version: 'v{BUILD_VERSION}',
traceAngularRoutes: false,
baseUrl: 'https://emergenceapi.azurewebsites.net',
useServerState: true,
useSignalR: true
};
......@@ -18,5 +18,6 @@ export const environment: any = {
version: 'Dev Version',
traceAngularRoutes: false,
baseUrl: 'http://localhost:60751',
useSignalR: false
useServerState: true,
useSignalR: true
};