|
P3-SDK 0.9
P3 Software Development Kit
|
GameAttributes are used to store common persistent data, such as operator settings, statistics, and high scores. DataManagerModes are modes that assist in managing sets of GameAttributes. GameAttributeManagerMode is a helper mode that is used for instantiating at least the 3 DataManagerModes that the game framework relies on: SettingsMode, StatisticsMode, and HighScoresMode.
To use the value of a GameAttribute in your game Mode, make a call to data.GetGameAttributeValue("<AttributeKey>").ToInt(), ToLong(), ToFloat(), ToDouble(), ToString(), or ToBool(). For example:
To update a stored GameAttribute in your game Mode, get a local instance of the GameAttribute, change the value as desired, and store the attribute. For example:
The P3App framework implements a number of GameAttributes that can be used by all games. These are used in 4 scopes: App-Specific GameAttributes, Playfield Module-Specific GameAttributes, Playfield Module Local GameAttributes, Global GameAttributes
These are saved independently per app. Key: "Settings" (This is also the default key. So access don't need to include the key).
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| Volume | Percentage of maximum volume | 0f | 1f | 0.02f | 0.2f |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| FreePlay | Allow games to be started with no credits | true | |||
| NumBonusCredits | Number of credits awarded for money bonus | 0 | 10 | 1 | 0 |
| NumCreditPointsRequiredForBonus | Number of Credit Points required before being awarded bonus credits | 2 | 20 | 1 | 8 |
| NumCreditPoints0 | Number of Credit Points for Money Switch 0 | 1 | 10 | 1 | 1 |
| NumCreditPoints1 | Number of Credit Points for Money Switch 1 | 1 | 10 | 1 | 1 |
| NumCreditPoints2 | Number of Credit Points for Money Switch 2 | 1 | 10 | 1 | 1 |
| NumCreditPointsPerGame | Number of Credit Points per Game | 1 | 10 | 1 | 2 |
Note - The total number of credits and the max allowable credit points are both global settings, described in the Global Credit GameAttributes section
A Credit Point is worth 1/NumCreditPointsPerGame, therefore the number of Credits is the number of Credit Points divided by NumCreditPointsPerGame. If the "number of Credit Points since the last game" >= NumCreditPointsRequiredForBonus, then NumBonusCredits many Credits are awarded as a bonus (and "the number of Credit Points since the last game" is decreased by NumCreditPointsRequiredForBonus without affecting the total number of Credit Points).
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| MaxPlayers | Maximum number of players per game | 1 | 9 | 1 | 4 |
| AllowPlayerRemoval | Allow players to be removed from game by holding the start button | true | |||
| NumBalls | Number of balls per game | 1 | 10 | 1 | 3 |
| SoftRestartEnabled | Allow aborting game by holding the start button | true | |||
| ServiceModeReset | Reset game when starting service mode | true | |||
| PlayGameIntro | Enable playing of the game intro | false | |||
| RandomizersEnabled | Allow randomizers to return random numbers (apps can use this GameAttribute; the framework doesn't make use of it. It just provides it for commonality with other apps) | true | |||
| CheatDetection | Detect cheaters (apps can use this GameAttribute; the framework doesn't make use of it. It just provides it for commonality with other apps) | 0 | 2 | 1 | 1 |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| FeatureMenuEnabled | Show feature menu when requested | true | |||
| ProfilesEnabled | Allow use of player profiles | true | |||
| AllowDefaultProfile | Allow setting of a default profile | true | |||
| ChangeProfileAllowed | Allow players to change profile | true | |||
| ManageProfilesAllowed | Allow players to manage profiles | true | |||
| TeamGamesAllowed | Team games allowed | true | |||
| SaveRestoreStateAllowed | Allow players to save/restore game state to/from their profile | true | |||
| SelectNoneProfileAllowed | Allow players to select the None profile, which is like never choosing a profile | true | |||
| SelectAddProfileAllowed | Allow players to select the Add Profile option, which will allow them to add a new profile | true | |||
| RequireProfileSelection | Don't allow players to back out of the profile selection menu. Force them to choose a profile | false | |||
| RequireProfileNameEntry | Re-enter the profile name entry dialog if it is completed with a blank name | false |
The above options determine what elements appear in the feature menu for profile-based features. You can dynamically set things like SelectNoneProfileAllowed and SelectAddProfileAllowed to true or false so that they show or don't show in various menus.
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| BallSearchSubsystemEnable | Allow ball searching | true | |||
| SearchInitialInactivityTime | Inactivity time (in seconds) before starting a ball search | 5 | 20 | 1 | 10 |
| SearchNextInactivityTime | Inactivity time (in seconds) before repeating a ball search | 5 | 20 | 1 | 10 |
| SearchTriesBeforeLaunch | Number of times to search before launching a new ball | 0 | 20 | 1 | 3 |
| SearchLaunchEnable | Automatically Launch a Chase Ball After x Failed Searches | true | |||
| WallScoopSearchEnable | Let Built-in wall/scoop search logic run | true |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| SlingshotPulseTime | Time (in milliseconds) to pulse slingshots when activated | 2 | 14 | 1 | 12 |
| SlingshotSwitchPolarity | Slingshot switch activation polarity, true for NO, false for NC. | true |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| TiltEnable | Tilt detection enable | false | |||
| TiltUseTiltBob | Use tilt bob for tilt detection | true | |||
| TiltWarnings | Number of warnings to issue before tilting | 0 | 10 | 1 | 2 |
| TiltWarningDelay | Time (in seconds) to wait between warning detects | 0f | 3f | 0.1f | 1.2f |
| TiltSettleDelay | Time (in seconds) to wait after tilting before "Evt_TiltSettled" is issued | 2 | 10 | 1 | 5 |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| UseSecondaryFlipperButtons | One-handed play enabled | false | |||
| UseOtherFlipperButtons | Use red buttons for all lower playfield flippers | false |
Despite its name, UseOtherFlipperButtons must be set to true to enable single-button control of the lower playfield flippers on each side.
By default, the colors of the three different LED strings in the backbox are controlled by a mode. An app can take control of the LEDs by running LED scripts at a higher priority than the BackboxColorsMode, but if it doesn't, the following GameAttributes set the colors of the backbox and allow the user to change them.
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| P3Red | Red value for backbox P3 RGB LEDs | 0 | 255 | 5 | 0 |
| P3Green | Green value for backbox P3 RGB LEDs | 0 | 255 | 5 | 0 |
| P3Blue | Blue value for backbox P3 RGB LEDs | 0 | 255 | 5 | 255 |
| PFRed | Red value for RGB LEDs mounted above upper playfield | 0 | 255 | 5 | 255 |
| PFGreen | Green value for RGB LEDs mounted above upper playfield | 0 | 255 | 5 | 255 |
| PFBlue | Blue value for RGB LEDs mounted above upper playfield | 0 | 255 | 5 | 255 |
| BackboxRed | Red value for RGB LEDs behind the translite in the backbox | 0 | 255 | 5 | 255 |
| BackboxGreen | Green value for RGB LEDs behind the translite in the backbox | 0 | 255 | 5 | 255 |
| BackboxBlue | Blue value for RGB LEDs behind the translite in the backbox | 0 | 255 | 5 | 255 |
The redemption GameAttributes are only used when your <AppCode>SettingsMode.redemptionEnabled property is true. Otherwise, none of the redemption GameAttributes will show up in the operator settings.
*Note - There is currently no code in the framework to handle ticket dispensing. These attributes are provided as starting points. Example code for ticket dispensing is available upon request from Multimorphic.
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| TicketsEnabled | Enable the ticket dispensing logic | false | |||
| TicketDispenseTimeout | Time (in seconds) to wait after last notch event before logging a dispense error | 0 | 1000 | 10 | 20 |
| TicketErrorDisplayLength | Time (in seconds) to display a dispense error message when an error is detected | 0 | 1000 | 10 | 20 |
| TicketsResetErrorCount | Reset the error count each game | false | |||
| TicketsErrorCount | Tickets earned but not dispensed due to dispenser error | 0 | 10000 | 1 | 0 |
| MinTicketAward | Base ticket payout | 0 | 100 | 1 | 2 |
| ForceTicketTest | Test: Force dispenser on | false |
These GameAttributes enable various popups and debug options.
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| BallsInPlayDebug | Enables popups when ballsInPlay changes (only if the app send Evt_BallsInPlay with the new number of balls in play when it should change) | false | |||
| LaunchDebug | Enables launch-related debug popups | false | |||
| LaunchFailedDebug | Enables debug popups for failed launches | false | |||
| EnableIRGridDebug | Shows on the playfield display a virtual version of the IR grid used for ball tracking | false | |||
| PopupDuration | Time (in seconds) to show debug popups | 1 | 10 | 1 | 3 |
The following GameAttribute is for setting the app's logging level (which types of log messages should be logged). By default, this is set to 0 (e.g. All) when simulating your app and 2 (e.g. Exception) when running on the P3 so the log doesn't get too big on location machines that are never turned off. For debugging issues with users, ask them to change their logging level to "All" (represented internally as 0).
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| LoggingLevel | Logging level | 0 | 4 | 1 | 0 |
See the Replays section for the GameAttributes related to Replays.
These are saved per playfield module. An example is a VUK launch strength that is tuned for the ball to eject with enough speed to reach a wireform or other feature. Another example is flipper strength, which might be tuned to be strong enough to flip a ball up a steep ramp on one playfield and might be weaker on single-level playfield to avoid damaging components. All apps that run against that playfield will use the saved setting. These are saved on the P3 so that if another of the same playfield is installed, the same settings will be used. Key: "PlayfieldModuleSettings"
These can be customized by creating a subclass of Multimorphic.P3App.Modes.Data.PlayfieldModuleSettingsMode and instantiating it in <AppCode>GameAttributeManagementMode, similar to how SettingsMode is subclassed and instantiated there.
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| launchStrengthMin<N> | Minimum pulse time for trough VUK N | 10 | 40 | 1 | 30 |
| launchStrengthMax<N> | Maximum pulse time for trough VUK N | 10 | 40 | 1 | 30 |
where N is the VUKNumber of a TroughLauncher, for example launchStrengthMin0 and launchStrengthMax0.
There will also be a LED Brightness setting for each LED String element, Collection of numbered LEDs and individual LEDs on the module (excluding the Base P3 LEDs).
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| LEDBrightness<LEDName> | Brightness for <LEDName> | 0f | 1f | 0.01f | 1f |
These are saved per playfield module and are saved on the playfield module. This allows playfield-specific calibration values to stay with the playfield module. Therefore, if the playfield is installed in another P3, software will load the saved calibration settings. Key: "PlayfieldModuleLocalSettings"
These can be customized by creating a subclass of Multimorphic.P3App.Modes.Data.PlayfieldModuleLocalSettingsMode and instantiating it in <AppCode>GameAttributeManagementMode, similar to how SettingsMode is subclassed and instantiated there.
These are saved to a global database accessible by all apps. This is useful for things like the strength of the staging coil, which needs to kick balls up into the P3's ball trough the same way, regardless of which playfield is installed or which app is running. Key: "GlobalSettings"
These can be customized by creating a subclass of Multimorphic.P3App.Modes.Data.GlobalSettingsMode and instantiating it in <AppCode>GameAttributeManagementMode, similar to how SettingsMode is subclassed and instantiated there.
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| NumCreditPoints | Number of credit points | 0 | 100 | 1 | 0 |
| NumCredits | Number of credits currently stored on the machine | 0 | 20 | 1 | 0 |
| MaxCreditPoints | Maximum allowed credit points | 10 | 500 | 5 | 100 |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| vukDrain | vukDrain Pulse Time | 4 | 30 | 1 | 16 |
| vukDrainStack | vukDrain Stack Pulse Time | 4 | 30 | 1 | 20 |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| BallTrackingPreset | Ball tracking preset configuration | 1 | 4 | 1 | 1 |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| exitRequiresCoinDoor | Exiting apps requires coin door open | true |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| TimeBeforeStartOfBallAutolaunch | Seconds to wait before auto-launching ball, in seconds. 0 waits forever. | 0 | 300 | 10 | 0 |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| Volume | Percentage of maximum volume | 0f | 1.0f | 0.02f | 0.2f |
| BluetoothEnabled | Enable Bluetooth system | false |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| SpeakerPanelBrightness | Brightness value for speaker panel | 0 | 255 | 5 | 255 |
These settings are only available to owners of the servo wall/scoop assembly:
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| AutoRefreshWallsScoops | Auto-refresh Walls/Scoops position | false | |||
| UpPosWall<N> | Up position for wall N | 35 | 255 | 1 | 180 |
| DownPosWall<N> | Down position for wall N | 35 | 255 | 1 | 75 |
| UpPosScoop<N> | Up position for scoop N | 35 | 255 | 1 | 180 |
| DownPosScoop<N> | Down position for scoop N | 35 | 255 | 1 | 75 |
| ScoopEntranceOperationStyle | Use both scoop optos to detect ball entry more accurately, but a bit slower. | false |
Where N is from 0 to 5 inclusive, for example UpPosWall0 and UpPosScoop0.
These settings are available to all owners, for use as directed by Multimorphic support:
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| ScoopMoatEntranceRetriggerDelay | Time to ignore repeat scoop entry events. Contact support for advice. | 0.05f | 1.0f | 0.05f | 0.30f |
| ScoopMoatExitRetriggerDelay | Time to ignore repeat scoop exit events. Contact support for advice. | 0.05f | 1.0f | 0.05f | 0.15f |
| Name | Description | Min | Max | Increment | Default |
|---|---|---|---|---|---|
| LEDBrightnessbackbox | Brightness for Backbox | 0f | 1f | 0.01f | 1f |
| LEDBrightnessbackboxBack | Brightness for Backbox Back | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnessbackboxBottom | Brightness for Backbox Bottom | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnessbackboxFront | Brightness for Backbox Front | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnessbackboxP3 | Brightness for Backbox P3 | 0f | 1f | 0.01f | 1f |
| LEDBrightnessbackboxTop | Brightness for Backbox Top | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnesscabinetBack | Brightness for Cabinet Back | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnesscabinetBottom | Brightness for Cabinet Bottom | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnesscabinetFront | Brightness for Cabinet Front | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnesscabinetTop | Brightness for Cabinet Top | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnessflasherSideModuleLeft | Brightness for Left Side | 0f | 1f | 0.01f | 1f |
| LEDBrightnessflasherSideModuleRight | Brightness for Right Side | 0f | 1f | 0.01f | 1f |
| LEDBrightnessplayfield | Brightness for Playfield | 0f | 1f | 0.01f | 1f |
| LEDBrightnessscoop | Brightness for Scoop | 0f | 1f | 0.01f | 0.4f |
| LEDBrightnessspeakerLeft | Brightness for Speaker Left | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnessspeakerRight | Brightness for Speaker Right | 0f | 1f | 0.01f | 0.14f |
| LEDBrightnesswall | Brightness for Wall | 0f | 1f | 0.01f | 0.4f |
| UseCustomBackboxLEDIndexes | Use custom backbox LED indexes | false | |||
| CustomBackboxLEDIndexFirst | First backbox LED index | 0 | 1363 | 1 | 682 |
| CustomBackboxLEDIndexLast | Last backbox LED index | 0 | 1363 | 1 | 1100 |
If you want to modify the default parameters for your game, override the CustomizeGameAttribute method with code that looks for the desired GameAttribute.Item field and then returns a modified GameAttributes.
Here's an example customization of a GameAttribute. The default attribute "NumBalls" defaults to a value of 3 and can be modified by the operator. This customization is used for a one ball game. It sets the value to 1, and hides it so it can't be modified by the operator.
From a subclass of SettingsMode :
If your game needs settings or statistics GameAttributes other than the defaults, or if you want to track specific high score categories, you can create a subclass of GameAttributeManagerMode and use it to instantiate subclasses of SettingsMode, StatisticsMode, and HighScoresMode.
Example P3SAGameAttributeManagerMode:
In your Multimorphic.P3App.Modes.Data.SettingsMode subclass, add a call to InitAttr(...) with parameters that define the new GameAttribute. These calls should typically go in an override of CreateDefaultAttrs(), which is the method used by the base class to create all of the default GameAttributes.
Example of subclassing CreateDefaultAttrs and adding a custom GameAttribute:
InitAttr() is a helper function with many variations that help create the GameAttributes and get them stored and tracked properly.
You might want to change the definition of a GameAttribute after users have deployed and run the app. Whether or not the changes force an update to the user's saved values is determined by Multimorphic.P3App.Data.GameAttributeCompareOptions. First decide what's used to determine the GameAttribute has changed (CompareAll, CompareAllExceptValue, CompareNone). Then, if it's determined to have changed, decide if the stored value should be updated based on UpdateValueIfAnyChange and UpdateValueIfDefaultChanged.
These GameAttributeCompareOptions can be passed in as a final parameter to the InitAttr calls. Example:
You can customize how the value of a GameAttribute is displayed on the screen by assigning custom ToString() methods. In the following example, the "SoundTrackRatio" GameAttribute is given a custom ToString() method:
To run specific code when certain GameAttributes are modified in the operator's ServiceMode Menu, you'll need to override the ProcessSavedAttributeEventHandler method in the subclass of the SettingsMode the GameAttribute is created in. Example:
Stock profiles allow GameAttribute settings to be forced to pre-determined values. All stock profiles are created at run-time as determined by code in your subclasses of GameAttributeManagerMode and SettingsMode. Simply override the GameAttributeManagerMode's CreateStockProfiles method and put in calls to the profileManagerMode's AddStockProfile method. Then make calls to an override of the SettingsMode's UpdateStockProfileAttributes method.
Here's an example that creates 5 stock profiles (Default, Easy, Medium, Hard, and Custom). Note that the boolean parameter in the call to UpdateProfileAttribute determines if the resulting stock profile's attribute is read-only or not. In this example, it's read-only for all except the "Custom" profile. This means that after activating the stock profile, the "NumAliens" GameAttribute won't be user-settable unless the activated profile was the "Custom" one.
Example code from a GameAttributeManagerMode subclass:
Example code from a SettingsMode subclass:
High Scores are managed internally as GameAttributes to provide persistence. <AppCode>GameAttributeManagerMode instantiates a HighScoresMode and sends it whatever HighScoreCategories are defined. Then when told to do so, the HighScoresMode compares player data against existing high scores for the category and prompts for name entry when new high scores are achieved. Apps can later request high score data to be sent to the GUI for each category, commonly during AttractMode.
Apps wanting the framework to help track high scores need to define one or more Multimorphic.P3App.Modes.Data.HighScoreCategory and tell the framework about it by posting ModeToMode "Evt_AddHighScoreCategory" events in <AppCode>GameAttributeManagerMode.mode_started().
A high score value is stored as a double to avoid the loss of precision at 10M with a float.
The HighScoreCategory constructor has this signature:
A HighScoreCategory has the following fields:
| Field | Type | Description |
|---|---|---|
| key | string | The player data key where the application stores the high score value with calls like data.currentPlayer.SaveData(key, scoreValue) |
| description | string | Description to be used in high score displays, more like a name. |
| numPlaces | int | Number of entries to store |
| defaultValues | List<double> | Default values for each entry |
| defaultNames | List<string> | Default player name for each entry |
| decimalPlaces | int | Number of decimals to show in high score displays |
| zeroValue | double | Value to use when the high score is reset by the user. Typically the worst possible score. Default is 0. |
| sortDirection | bool | false = larger is better (default), true = smaller is better. |
| disallowedForRestoredGames | bool | true = restored games not eligible for this high score, false = restored games are eligible. |
| eventName | string | Event Profile associated with this category. Default is null for regular high scores. |
Example code in <AppCode>GameAttributeManagerMode.mode_started():
This happens automatically when processing end of game if <AppCode>BaseGameMode.highScoreCheckEnabled is true. If you want high score comparisons to run at another time, set <AppCode>BaseGameMode.highScoreCheckEnabled to false and post ModeToMode event "Evt_LookForHighScores".
Framework code will receive that event and initiate high score checks against the player data, as referenced by the high score categories. If a new high score was achieved, the player will be prompted to enter his or her name. When comparisons and entry are completed, the internal logic posts "Evt_HighScoreEntryFinished". So handle that if you are setting <AppCode>BaseGameMode.highscoreCheckEnabled to false, because that's what allows the end of game processing to finish.
In most games, the app will initiate the appearance of the high score tables. This is done by posting the ModeToMode event "Evt_ShowHighScores" with an int parameter representing the category to show. To cycle through more tables, continue posting that event with an incremented or decremented index. It's common to map the right flipper button to increment through the high score tables and the left flipper button to decrement through the high score tables.
To stop displaying the high score tables, issue the "Evt_HideHighScores" event:
When "Evt_ShowHighScores" event is received by the internal high score processing logic, it will prepare a Multimorphic.P3App.Modes.Data.HighScoreDisplayData object and post it to the GUI through the ModeToGUI event "Evt_ShowHighScores".
Then when the "Evt_HideHighScores" event is received, it will reissue the "Evt_HideHighScores" event to the GUI.