The files in the common directory provide a library of generic pinball functions that can be reused from game to game. Some of the more important ones are described in detail in this chapter.
FreeWPC implements a weak form of coin switch handling. It is not very robust and does not time the coins as it should.
If FREE_ONLY
is defined, it will build a ROM that doesn't require
coins.
This module tracks lit and collected extra balls. Lit extra balls can be easy (lit until end of game) or hard (lit only until end of ball).
In the machine config file, you should tag the lamp that indicates
an extra ball is lit as extra-ball
, and the shoot again lamp
as shoot-again
. Then the lamps will automatically update for you
when these APIs are called.
light_easy_extra_ball
light_hard_extra_ball
eb_light_adjustable
collect_extra_ball
can_award_extra_ball
There is also an API special_award
to award a special, but
it does not manage any lamps automatically. It just obeys the adjustment
to award whatever has been configured for special, and fires the knocker.
FreeWPC implements a tournament mode module. Note this is what newer Stern games refer to as competition mode.
Tournament mode can be enabled globally in the adjustments menu, or it can be enabled by holding down the left flipper button briefly before starting the game. A message will indicate that tournament mode has been enabled. It affects all players in the game.
Software should check the tournament_mode_enabled
boolean variable
to determine if tournament is in effect.
Machines don't need to do much to produce a working ball search function.
The common code knows how to pulse all of the regular solenoids.
It also knows not to fire anything marked as a motor
or flasher
.
You can mark a solenoid in the machine description with nosearch
to ignore other solenoids as well.
Machines that need to handle a particular power driver in a non-standard
way (by using a template driver) should implement a ball_search
event handler, and mark the
associated solenoid as nosearch
.
The ball_search
handlers will be called along with the automatic
pulsing.
For example, on Funhouse, the Rudy saucer eject needs to make sure that the mouth is open before kicking.
Solenoids associated with ball devices will be skipped unless they are empty, except after several ball searches have failed. The chase ball/lost ball recovery feature is also implemented and can be enabled by menu adjustment.
Game code can call ball_search_timeout_set
to set the amount of
idle time that must expire before a ball search will occur. The default
is 15 seconds. The timer resets anytime a playfield switch (one marked
with the SW_PLAYFIELD
flag) triggers. You can also manually reset it
manually using ball_search_timer_reset
.
Call knocker_fire
to fire the knocker. If a coin meter is attached
to the knocker coil, it will not be pulsed. If the machine defines a sound
effect for knock, that will be played instead of pulsing a solenoid.
Adjustments are 8-bit variables kept in persistent storage. Each group of related adjustments is checksummed to verify integrity. Adjustments can be checked by just reading the variable; there is no special API to do so.
Machines can define their own feature adjustments in the machine config.
Audits are 16-bit variables kept in the non-volatile area of memory. They
are generally incremented via the audit_increment
API, which adds 1.
They can also be incremented by an arbitrary value, via audit_add
; or
they can be assigned via audit_assign
. They will not overflow if the
maximum value is reached, but instead will just stop counting up.
Machines can define their own feature audits in the machine config.
A global playfield multiplier is supported; use score_multiplier_set
to
change it. It is automatically set to 1 at the beginning of each ball.
Scores can be stated in two ways: as a 5-byte, binary-coded decimal value, or as an 8-bit "score code". The long values allow for arbitrary values up to 10 billion points. The short values are more compact and index a table of common score values, which are listed in the machine config.
The first set of APIs operate on arbitary BCD score buffers:
score_zero
score_copy
score_add
score_sub
score_mul
score_compare
The second group of APIs increment the current player's score by a fixed value.
score
score_long
score_multiple
score()
, but also takes a multiplier argument. This multiplier
and the global score multiplier are taken into account.
score_long_multiple
score_long
and score_multiple
. This is the most
low-level API; all others ultimately call it.
score_long_unmultiplied
The third group of APIs, called the ladder APIs, add score according to some rule.
A fixed ladder rule tracks the current value of a shot, and defines a base value, an increment, and a maximum value.
fixed_ladder_reset
fixed_ladder_advance
fixed_ladder_score
fixed_ladder_scorex
fixed_ladder_score_and_advance
fixed_ladder_scorex_and_advance
A lamp timer is a countdown timer which is tied to a playfield lamp. The amount of time remaining controls how fast the lamp flashes. When the timer reaches zero, the effect stops.
You declare a structure of type struct lamptimer_args
, which
names the lamp and the initial timer value, in seconds.
The lamp is modified as part of an internally generated lamp effect (meaning that it behaves just like a leff, but it does not have a lamp effect ID); thus, the basic state of the lamp is retained. While the lamp timer runs, the basic state is overriden by the effect.
lamp_timer_start
lamp_timer_find
lamp_timer_stop
The score rank module is optional, based on the value of CONFIG_SCORE_RANK
.
When enabled, the system will
monitor the relative changes in players' scores over the course of a multi-
player game, and throw a rank_change
event whenever the current player
moves into a new place. It is up to each game to decide how to handle it.
To write a timed mode, you need to do two things:
First, create a structure of type struct timed_mode_ops
and fill out
all of the required information. Use the DEFAULT_MODE macro in the initializer
to set suitable values before declaring your own values. The fields are:
GID
.
This field is mandatory and has no default. When the mode is started, a task will be created with this group ID.
system_timer_pause
when the mode should pause for the "usual cases" only.
Use null_false_function
if the mode should not pause at all. You can also
supply your own function if you need custom behavior.
You must make sure that the structure and all of the functions that it references are in the same .c file, otherwise ROM paging will not work.
Second, handle several system events which affect the mode's operation:
timed_mode_music_refresh.
music_refresh
handler, passing it a pointer to the mode ops struct.
timed_mode_display_update.
display_update
handler, passing it a pointer to the mode ops struct.
From outside the mode itself, other modules call these APIs to interact with your mode. The mode ops struct is part of the public interface.
timed_mode_begin
timed_mode_end
timed_mode_reset.
timed_mode_add.
timed_mode_get_timer.
timed_mode_running_p
timed_mode_effect_running_p
timed_mode_device_running_p
device_update
function.
The ball serve module is the preferred API for adding balls to play. It uses the ball tracking APIs to program the ball trough, but adds support for autoplunging and multiball logic.
The system supports games with autoplungers or manual plungers. Auto launch support requires that the machine defines three things: the launch button switch, the launch solenoid, and a shooter switch.
The base API serve_ball
simply kicks a ball out of the trough.
It also resets the valid playfield flag and refreshes background effects.
This is the same call made by the game state machine during start ball.
Use serve_ball_auto
instead if you want the ball to be autolaunched
as soon as it is served successfully. Otherwise, it is identical to
serve_ball
. If
a ball is served without autolaunch, it can be launched later by calling
launch_ball
. This happens automatically when the launch button is
pressed and a ball is detected in the shooter lane.
You normally do not need to call either of those APIs, except in some rare cases.
The preferred way to start multiballs is to use set_ball_count
,
which sets the number of balls in play, or add_ball_count
if you
want to say how many balls to be added. These use serve_ball_auto
to do the work. They work on manual plunger games too. Only one ball
will ever be placed in the shooter at a time.
serve_ball
serve_ball_auto
launch_ball
set_ball_count
add_ball_count
Multiball modes can be implemented by defining a structure of type
struct mb_mode_ops
. They are modeled after the way that timed
modes are constructed. Use the DEFAULT_MBMODE macro in the initializer
to set suitable values before declaring your own values.
The key difference is how the mode ends; here, we examine the number of balls in play and end the mode when it reduces to 1.
FreeWPC implements the Mute and Pause feature that was included in the Twilight Zone home ROM. It is optional at compile-time. The machine must have an extra-ball buyin button for it to work.
When compiled in, and the adjustment "MUTE/PAUSE" is set to YES, then pressing buyin during a game will hold the flippers, disable ball kickouts, pause timers, and turn off the background music. To continue, press the button again. It will also timeout automatically after 15 minutes.
A default status report is builtin which shows basic game information. To activate it in a game, hold in either flipper button for about 5 seconds.
Machines can customize the report by defining their own status pages.
Modules should declare a handler for the status_report
event.