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

Feature/wpc integrationtest #168

Merged
merged 4 commits into from
Nov 18, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
116 changes: 1 addition & 115 deletions lib/emu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Visual PinMAME Control

### STATS:
### STATS

A quick evaluation of 357 VPX VBS files, showed this amount of API Calls

Expand Down Expand Up @@ -49,43 +49,6 @@ A quick evaluation of 357 VPX VBS files, showed this amount of API Calls
- .B2SSetData 505
- .GetMech 38

### STATE
Should be implemented - BASIC

#### PoC

```
const Control = {
gameName: '',
running: false,
pause: false,
get GameName() {
return this.gameName;
},
set GameName(gameName) {
this.gameName = gameName;
},
get Running() {
return this.running;
},
get Pause() {
return this.pause;
},
set Pause(pause) {
this.pause = pause;
},
get Version() {
return '1.10.11';
},
Run() {
console.log('BOO HOO');
},
Stop() {
console.log('STOP');
}
}
```

### Properties

- GameName, Read/Write: Initializes VPinMAME for game "gameName". Example Controller.GameName = "tz_94h"
Expand All @@ -102,28 +65,6 @@ minVersion: Minimum version of Visual PinMAME (e.g. 100 for 1.00) required to ru

## Game Settings

### STATE
Should be implemented.

#### PoC

```
const GameSetting = {
get Dip() {
//TODO unclear
},
set Dip(dipBankNumber) {
//TODO unclear
},
get WPCNumbering() {
return this.pause;
},
get SampleRate() {
return 22050;
},
}
```

### Properties

- Dip (Dip Bank Number), Read/Write, Sets/Gets the Dip switch settings for the current game. Dip Bank Number: dip 1-8 = bank 0, dip 9-16 = bank 1 ... value: binary value to set the dips 1=On, 0=Off. Example: Controller.Dip(0) = &H55, Controller.Dip(1) = &Haa
Expand All @@ -133,9 +74,6 @@ const GameSetting = {

## Customization

### STATE
Will skip implementation unless we need.

### Properties

- SplashInfoLine, Read/Write, Game credits to display in startup splash screen. Example: Controller.SplashInfoLine = "Game design by ..."
Expand Down Expand Up @@ -169,36 +107,12 @@ Controller.CheckROMS(0,hWnd) : Displays the results of the ROM check (hWnd = Han

## Aggregate Polling Functions


These properties return a matrix with everything that has changed since the last call.
The array contains the following info
Matrix(0,0) Number of first changed item
Matrix(0,1) New status of first item
Matrix(1,0) Number of second changed item

### STATE
Should be implemented - BASIC

#### PoC

```
const AggregatePollingFunctions = {
get ChangedLamps() {
return x;
},
get ChangedSolenoids() {
return x;
},
get ChangedGI() {
return x;
},
get ChangedLEDs() {
return '1.10.11';
},
}
```


### Properties

- ChangedLamps, Read Only, Returns which lamps have changed since last call to this property!
Expand All @@ -208,28 +122,6 @@ const AggregatePollingFunctions = {

## Game Input/Output

### STATE
Should be implemented - BASIC

#### PoC

```
const GameInputOutput = {
get Lamp(number) {
return x;
},
get Solenoid(number) {
return x;
},
get GIString(number) {
return x;
},
get Switch(number) {
return x;
},
}
```

### Properties

- Lamp(number), Read Only, Get status of a single lamp, return: True = Lamp on, False = Lamp off
Expand All @@ -239,9 +131,6 @@ const GameInputOutput = {

## Debugging

### STATE
Will skip implementation unless we need.

### Properties

- ShowDMDOnly, Read/Write, Enable/disable VPinMAME status matrices.
Expand All @@ -250,9 +139,6 @@ Will skip implementation unless we need.

## Events

### STATE
Will skip implementation unless we need.

May not be supported in all scripting environments!

- OnSolenoid(solenoidNo, isActive), Called whenever a solenoid changes state
Expand Down
4 changes: 2 additions & 2 deletions lib/emu/emulator-state.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ describe('The EmulatorState - handle state changes', () => {
expect(emulatorState.getChangedLamps()).to.deep.equal([]);
});

it('should return empty array after fetching ChangedLEDs - not implemented used for Alphanumeric displays only', () => {
const result: number[][] = emulatorState.ChangedLEDs();
it('should return empty array after fetching getChangedLEDs - not implemented used for Alphanumeric displays only', () => {
const result: number[][] = emulatorState.getChangedLEDs();
expect(result).to.deep.equal([]);
});

Expand Down
2 changes: 1 addition & 1 deletion lib/emu/emulator-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class EmulatorState {
}

// NOT IMPLEMENTED YET - needed for alphanumeric games only!
public ChangedLEDs(): number[][] {
public getChangedLEDs(): number[][] {
return [];
}

Expand Down
136 changes: 136 additions & 0 deletions lib/scripting/objects/vbs-to-wpcemu.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* VPDB - Virtual Pinball Database
* Copyright (C) 2019 freezy <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import * as chai from 'chai';
import { expect } from 'chai';
import * as sinon from 'sinon';
import { SinonStub } from 'sinon';
import { TableBuilder } from '../../../test/table-builder';
import { Player } from '../../game/player';
import { Emulator } from '../../emu/wpc-emu';
import { EmulatorState } from '../../emu/emulator-state';

/* tslint:disable:no-unused-expression no-string-literal */
chai.use(require('sinon-chai'));
describe('VpmController integration test', () => {

const sandbox = sinon.createSandbox();
let setSwitchInputSpy: SinonStub<[number, boolean?]>;
let setDipSwitchByteSpy: SinonStub<[number]>;
let getSolenoidSpy: SinonStub<[number]>;
let getLampSpy: SinonStub<[number]>;
let getChangedLampsSpy: SinonStub<any>;
let getChangedSolenoidsSpy: SinonStub<any>;
let getChangedGISpy: SinonStub<any>;
let getChangedLEDsSpy: SinonStub<any>;

beforeEach(() => {
setSwitchInputSpy = sandbox.stub(Emulator.prototype, 'setSwitchInput').returns(true);
setDipSwitchByteSpy = sandbox.stub(Emulator.prototype, 'setDipSwitchByte');
getSolenoidSpy = sandbox.stub(Emulator.prototype, 'getSolenoidState');
getLampSpy = sandbox.stub(Emulator.prototype, 'getLampState');
getChangedLampsSpy = sandbox.stub(EmulatorState.prototype, 'getChangedLamps');
getChangedSolenoidsSpy = sandbox.stub(EmulatorState.prototype, 'getChangedSolenoids');
getChangedGISpy = sandbox.stub(EmulatorState.prototype, 'getChangedGI');
getChangedLEDsSpy = sandbox.stub(EmulatorState.prototype, 'getChangedLEDs');
neophob marked this conversation as resolved.
Show resolved Hide resolved
});

afterEach(() => {
sandbox.restore();
});

function setupPlayerTable(vbs) {
const scope = {};
const table = new TableBuilder().withTableScript(vbs).build('Table1');
new Player(table).init(scope);
}

it('VBS should update switch, Controller.Switch()', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.Switch(49) = 0\nController.Switch(51) = 1`;
setupPlayerTable(vbs);
expect(setSwitchInputSpy.args.length).to.equal(2);
expect(setSwitchInputSpy.args[0]).to.deep.equal([ 49, false ]);
expect(setSwitchInputSpy.args[1]).to.deep.equal([ 51, true ]);
});

it('VBS should update language setting, Controller.DIP()', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.DIP(0) = &H00`;
setupPlayerTable(vbs);

expect(setDipSwitchByteSpy.args.length).to.equal(1);
expect(setDipSwitchByteSpy.args[0]).to.deep.equal([ 0 ]);
});

it('VBS should update language setting, Controller.Dip()', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.Dip(0) = &H70`;
setupPlayerTable(vbs);

expect(setDipSwitchByteSpy.args.length).to.equal(1);
expect(setDipSwitchByteSpy.args[0]).to.deep.equal([ 112 ]);
});

it('VBS should read solenoid, Controller.Solenoid()', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.Solenoid(4)`;
setupPlayerTable(vbs);

expect(getSolenoidSpy.args.length).to.equal(1);
expect(getSolenoidSpy.args[0]).to.deep.equal([ 4 ]);
});

it('VBS should read lamp, Controller.Lamp()', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.Lamp(3)`;
setupPlayerTable(vbs);

expect(getLampSpy.args.length).to.equal(1);
expect(getLampSpy.args[0]).to.deep.equal([ 3 ]);
});

it('VBS should read changed lamp, Controller.ChangedLamps', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.ChangedLamps`;
setupPlayerTable(vbs);

expect(getChangedLampsSpy.args.length).to.equal(1);
expect(getChangedLampsSpy.args[0]).to.deep.equal([ ]);
});

it('VBS should read changed lamp, Controller.ChangedGI', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.ChangedGI`;
setupPlayerTable(vbs);

expect(getChangedGISpy.args.length).to.equal(1);
expect(getChangedGISpy.args[0]).to.deep.equal([ ]);
});

it('VBS should read changed lamp, Controller.ChangedSolenoids', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.ChangedSolenoids`;
setupPlayerTable(vbs);

expect(getChangedSolenoidsSpy.args.length).to.equal(1);
expect(getChangedSolenoidsSpy.args[0]).to.deep.equal([ ]);
});

it('VBS should read changed lamp, Controller.ChangedLEDs', () => {
const vbs = `Dim Controller\nSet Controller = CreateObject("VPinMAME.Controller")\nController.ChangedLEDs`;
setupPlayerTable(vbs);

expect(getChangedLEDsSpy.args.length).to.equal(1);
expect(getChangedLEDsSpy.args[0]).to.deep.equal([ ]);
});

});
10 changes: 7 additions & 3 deletions lib/scripting/objects/vpm-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class VpmController {
private splashInfoLine: string = '';
private readonly player: Player;
public readonly Dip: { [index: number]: number };
public readonly DIP: { [index: number]: number };
public readonly Switch: { [index: number]: number };
public readonly Lamp: { [index: number]: number };
public readonly Solenoid: { [index: number]: number };
Expand Down Expand Up @@ -75,6 +76,9 @@ export class VpmController {
return true;
},
);
// See https://github.com/vpdb/vpx-js/issues/163
this.DIP = this.Dip;

this.Lamp = this.createGetSetNumberProxy('LAMP',
(index) => this.emulator.getLampState(index), SET_NOP);
this.Solenoid = this.createGetSetNumberProxy('SOLENOID',
Expand Down Expand Up @@ -256,7 +260,7 @@ export class VpmController {
return this.emulator.emulatorState.getChangedGI();
}
get ChangedLEDs(): number[][] {
return this.emulator.emulatorState.ChangedLEDs();
return this.emulator.emulatorState.getChangedLEDs();
}

// Debugging
Expand Down Expand Up @@ -284,9 +288,9 @@ export class VpmController {
setFunction: (prop: number, value: number) => boolean,
): { [index: number]: number } {
const handler = {
get: (target: {[ index: number ]: number}, prop: number): number => {
get: (target: {[ index: number ]: number}, prop: number | string): number => {
logger().debug('GET', name, {target, prop});
return getFunction(prop);
return getFunction(parseInt(prop.toString(), 10));
},

set: (target: {[ index: number ]: number}, prop: number | string, value: number): boolean => {
Expand Down