diff --git a/lib/emu/README.md b/lib/emu/README.md index a82dcb48..14d233bf 100644 --- a/lib/emu/README.md +++ b/lib/emu/README.md @@ -2,7 +2,7 @@ ## Visual PinMAME Control -### STATS: +### STATS A quick evaluation of 357 VPX VBS files, showed this amount of API Calls @@ -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" @@ -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 @@ -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 ..." @@ -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! @@ -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 @@ -239,9 +131,6 @@ const GameInputOutput = { ## Debugging -### STATE -Will skip implementation unless we need. - ### Properties - ShowDMDOnly, Read/Write, Enable/disable VPinMAME status matrices. @@ -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 diff --git a/lib/emu/emulator-state.spec.ts b/lib/emu/emulator-state.spec.ts index 262134fd..b83344ac 100644 --- a/lib/emu/emulator-state.spec.ts +++ b/lib/emu/emulator-state.spec.ts @@ -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([]); }); diff --git a/lib/emu/emulator-state.ts b/lib/emu/emulator-state.ts index 1a7439f9..0e873874 100644 --- a/lib/emu/emulator-state.ts +++ b/lib/emu/emulator-state.ts @@ -100,7 +100,7 @@ export class EmulatorState { } // NOT IMPLEMENTED YET - needed for alphanumeric games only! - public ChangedLEDs(): number[][] { + public getChangedLEDs(): number[][] { return []; } diff --git a/lib/scripting/objects/vbs-to-wpcemu.spec.ts b/lib/scripting/objects/vbs-to-wpcemu.spec.ts new file mode 100644 index 00000000..c5f0e6d6 --- /dev/null +++ b/lib/scripting/objects/vbs-to-wpcemu.spec.ts @@ -0,0 +1,126 @@ +/* + * VPDB - Virtual Pinball Database + * Copyright (C) 2019 freezy + * + * 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 { 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(); + + 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 setSwitchInputSpy = sandbox.stub(Emulator.prototype, 'setSwitchInput').returns(true); + 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 setDipSwitchByteSpy = sandbox.stub(Emulator.prototype, 'setDipSwitchByte'); + 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 setDipSwitchByteSpy = sandbox.stub(Emulator.prototype, 'setDipSwitchByte'); + 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 getSolenoidSpy = sandbox.stub(Emulator.prototype, 'getSolenoidState'); + 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 getLampSpy = sandbox.stub(Emulator.prototype, 'getLampState'); + 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 getChangedLampsSpy = sandbox.stub(EmulatorState.prototype, 'getChangedLamps'); + 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 getChangedGISpy = sandbox.stub(EmulatorState.prototype, 'getChangedGI'); + 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 getChangedSolenoidsSpy = sandbox.stub(EmulatorState.prototype, 'getChangedSolenoids'); + 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 getChangedLEDsSpy = sandbox.stub(EmulatorState.prototype, 'getChangedLEDs'); + 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([ ]); + }); + +}); diff --git a/lib/scripting/objects/vpm-controller.ts b/lib/scripting/objects/vpm-controller.ts index f7171d01..513b4ba1 100644 --- a/lib/scripting/objects/vpm-controller.ts +++ b/lib/scripting/objects/vpm-controller.ts @@ -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 }; @@ -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', @@ -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 @@ -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 => {