Beispiel #1
0
CALLSET_ENTRY (multiball, valid_playfield)
{
	if (balls_locked == 1)
	{
		callset_invoke (wheel_award_jackpot_lit);
		if (device_recount (dev) > 0)
			device_request_empty (dev);
	}
}
Beispiel #2
0
static void set_ball_count_task (void) {
	device_t *dev = device_entry (DEVNO_TROUGH);
	U8 max_live_balls;
	U8 retries;
	U8 	temp_live_balls_wanted;

	max_live_balls = live_balls;
	temp_live_balls_wanted = live_balls_wanted - live_balls;
	retries = 2;

	//first pass - quick fire balls
	MB_SERVING = TRUE;
	while (temp_live_balls_wanted) {
		temp_live_balls_wanted--;
		sol_request_async (SOL_BALLSERVE);
		task_sleep (TIME_500MS); //worked good at 700 - just giving a little margin here
		task_sleep (TIME_400MS);
		sol_request_async (MACHINE_LAUNCH_SOLENOID);
		task_sleep (TIME_500MS);//worked good at 300 - just giving a little margin here
	}//end of rapid fire serving
	MB_SERVING = FALSE;

	//check trough to see if live balls is accurate
			task_sleep (TIME_1S);
			live_balls = (5 - device_recount(device_entry (DEVNO_TROUGH)) );
			max_live_balls = live_balls;

	//if still not all balls out there, retry slower - 2 times
	// we will usually arrive at this place on a ball-saving type multiball
	//where balls are constantly draining and refiring
	//this is okay, since the refiring will slow down which is sort of a punishment to
	//the player for allowing the balls to drain so fast
	while (max_live_balls < live_balls_wanted && retries) {
		retries--;

		/* Are there enough balls in the trough to satisfy another kick request?
		 * If not, then we need to add the balls from somewhere else.*/
		if (dev->actual_count < dev->kicks_needed)	callset_invoke (trough_rescue);
		else										serve_ball_auto ();

		task_sleep (SET_BALL_COUNT_TASK_DELAY);

		/* As long as there is a ball on the shooter, wait before trying
		to continue.  This flag will clear once the shooter switch
		has cleared for a few seconds. */
		while (global_flag_test (GLOBAL_FLAG_BALL_AT_PLUNGER))
			task_sleep (TIME_133MS);

		/* See if the ball count went up, indicating success */
		if (live_balls > max_live_balls)
			max_live_balls = live_balls;
	}//end of retry section

	task_exit ();
} //end of function
Beispiel #3
0
CALLSET_ENTRY (ball_lock, trunk_back_shot)
{
	if (ball_lock_can_be_collected () && balls_locked < 2)
	{
		device_t *dev = device_entry (DEVNO_SUBWAY);
		if (device_recount (dev) < 2)
		{
			device_lock_ball (dev);
		}
		else
		{
			/* start kickout warning effect */
		}
		ball_lock_award ();
	}
}
Beispiel #4
0
CALLSET_ENTRY (multiball, dev_wire_ball_lock_enter)
{
	if (!in_game)
		return;
	if (can_lock_ball)
	{
		if (device_recount (dev) < 2)
			device_lock_ball (dev);
		bounded_increment (balls_locked, 2);
		
		head_desired = FACE_2;
		callset_invoke (check_head_face);
		
		deff_start (DEFF_BALL_LOCKED);
		callset_invoke (ball_locked);
	}
}
Beispiel #5
0
/** Probes all devices to see if any balls are present that
 * shouldn't be.  Balls are kicked as necessary.
 *
 * For example, this clears out the balls of a lockup device
 * at the end of a game.
 *
 * This is always done as a background task, because it may
 * take some time and this function waits for any kicked
 * balls to successfully exit before it returns.
 */
void device_probe (void)
{
	devicenum_t devno;
	U8 kicks;

	dbprintf ("Probing devices\n");

	/* Keep track of the number of times we actually had to kick
	a device; equivalently, this is the number of times we sleep
	waiting for the kick to have an effect.  After so long, if
	things aren't right, just give up. */
	kicks = 0;

probe_from_beginning:
	if (kicks >= 10)
		goto probe_exit;

	for (devno = 0; devno < NUM_DEVICES; devno++)
	{
		device_t *dev = device_entry (devno);

		/* Recount the number of balls in the device, and reset
		 * other device data. */
		device_recount (dev);
		dev->previous_count = dev->actual_count;
		dev->kicks_needed = 0;
		dev->kick_errors = 0;
		task_kill_gid (DEVICE_GID(devno));

		/* If there are more balls in the device than ought to be,
		 * schedule the extras to be emptied.   Then rescan from
		 * the beginning again. */
		dev->max_count = dev->props->init_max_count;
		if (dev->actual_count > dev->max_count)
		{
			kicks++;
			device_request_kick (dev);
			task_sleep_sec (2);
			goto probe_from_beginning;
		}
#if 0 /* TODO */
		else if (dev->actual_count < dev->max_count)
		{
			/* The device normally holds more balls than are present in
			it.  If possible, launch a ball here.  (For example, ST:TNG
			or Whodunnit.) */
		}
#endif
	}

probe_exit:
	/* At this point, all kicks have been made, but balls may be
	on the playfield heading for the trough.  We still should wait
	until 'missing_balls' goes (hopefully) to zero.
	We'll wait for up to 10 seconds, but exit sooner if we find all
	balls before then. */
	task_sleep_sec (4);
	if (missing_balls != 0)
	{
		task_sleep_sec (2);
		if (missing_balls != 0)
		{
			task_sleep_sec (2);
			if (missing_balls != 0)
			{
				task_sleep_sec (2);
			}
		}
	}

	dbprintf ("Checking globals after probe\n");
	device_update_globals ();

	dbprintf ("\nDevices initialized.\n");
	device_debug_all ();
	task_exit ();
}
Beispiel #6
0
/** The core function for handling a device.
 * This function is invoked (within its own task context) whenever
 * a switch closure occurs on a device, or when a request is made to
 * kick a ball from a device.
 * The update task will get killed and restarted anytime a switch
 * closure occurs on the device, so it may be interrupted, but only
 * while it is sleeping.
 */
void device_update (void)
{
	device_t *dev = &device_table[device_getgid () - DEVICE_GID_BASE];

wait_and_recount:
	/* We are really interested in the total count of the
	 * device, not which switches contributed to it.
	 * Since multiple switch transitions occur as a ball
	 * "slides through", don't act on a transition right
	 * away.  Instead, wait awhile until no further transitions
	 * occur, so that the count is stable.  If another closure on
	 * this device happens while we sleep here, this task will
	 * be killed and restarted.
	 */
	task_sleep (dev->props->settle_delay);

start_update:
	task_sleep (TIME_50MS);

	/* The device is probably stable now.  Poll all of the
	 * switches and recount */
	device_recount (dev);

	device_update_globals ();
	device_debug (dev);

	dbprintf ("Updating device %s\n", dev->props->name);

	/*****************************************
	 * Handle "count" changes
	 *****************************************/
	if (dev->state == DEV_STATE_IDLE)
	{
		/* Device is idle */
		if (dev->actual_count == dev->previous_count)
		{
			/* Switch closures were detected but in the end, after becoming
			 * stable, the count did not change.  This is OK, perhaps
			 * there is some vibration...
			 * Also, when transitioning back to idle after a device kick,
			 * we repoll the switches one extra time and if all is well,
			 * we'll end up here.
			 */
		}
		else if (dev->actual_count < dev->previous_count)
		{
			/* Also unusual in that a ball came out of the device without
			 * explicitly kicking it.  (Although this can happen in test mode.)
			 * Note that the number of balls in play went up */
			if (in_game)
			{
				device_call_op (dev, surprise_release);
				device_add_live ();
			}
		}
		else if (dev->actual_count > dev->previous_count)
		{
			/* More typical : when idle, the count should only go up.
			 * Treat this as an enter event (or multiple events, if the
			 * count goes up by more than 1). */
			U8 enter_count = dev->actual_count - dev->previous_count;
			if (!trough_dev_p (dev))
				set_valid_playfield ();
			while (enter_count > 0)
			{
				callset_invoke (any_device_enter);
				device_call_op (dev, enter);
				enter_count--;
			}
		}
	}
	else if ((dev->state == DEV_STATE_RELEASING) && (dev->kicks_needed > 0))
	{
		/* Device is in the middle of a release cycle.
		 * See if the count changed. */
		if (unlikely (dev->actual_count >= dev->previous_count))
		{
			/* After attempting a release, the count did not go down ... the kick
			 * probably failed, and we should retry up to a point.  Since dev->state
			 * is unchanged below, the kick attempt will get reinvoked. */

			/* Note: during multiball, it is possible for a second ball to enter
			the device immediately after the kick.  The kick didn't
			really fail, but there's no way to tell the difference. */

			dev->kick_errors++;
			dbprintf ("Kick error %d\n", dev->kick_errors);
			device_call_op (dev, kick_failure);

			if (dev->kick_errors == (trough_dev_p (dev) ? 20 : 7))
			{
				/* OK, we tried too many times and still no ball came out.
				 * Cancel all kick requests for this device unless it is
				 * the trough */
				nonfatal (ERR_FAILED_KICK);
				dev->kicks_needed = 0;
				dev->state = DEV_STATE_IDLE;
			}
			else
			{
				/* Wait awhile before trying again.  The more we fail, the longer
				the delay in between tries. */
				if (dev->kick_errors <= 3)
					task_sleep_sec (1);
				else
					task_sleep_sec (5);
			}
		}
		else if (dev->actual_count < dev->previous_count)
		{
			/* The count decreased as expected.
			 * As we only kick 1 ball at a time, then really it
			 * only should have gone down by 1, but the logic
			 * should work even if more than 1 ball is ejected. */
			U8 kicked_balls = dev->previous_count - dev->actual_count;

			/* If too many balls were kicked, throw an error.
			Only process as many as were requested. */
			if (kicked_balls > dev->kicks_needed)
			{
				nonfatal (ERR_KICK_TOO_MANY); /* akin to ERR_IDLE_BALL_LOST */
				kicked_balls = dev->kicks_needed;
			}

			/* Throw a kick success event for each ball that was kicked */
			while (kicked_balls > 0)
			{
				device_call_op (dev, kick_success);
				dev->kicks_needed--;
				kicked_balls--;
			}

			/* Go back to idle state.  If there are more kicks left, we will
			switch back to DEV_STATE_RELEASING again later.  The point is not to
			stay in DEV_STATE_RELEASING when we have not actually kicked the ball;
			if the request is held up for some reason, we want switch closures to
			be processed correctly. */
			dev->state = DEV_STATE_IDLE;
		}
	}

	/*****************************************
	 * Handle global count changes
	 *****************************************/
	device_update_globals ();

	/************************************************
	 * Handle counts larger than the device supports
	 ************************************************/
	if (dev->kicks_needed == 0 && dev->actual_count > dev->max_count)
	{
		/* When there are more balls in the device than we normally want
		to keep here, we must kick one of them out.  If multiple kicks
		are needed, this check will occur again in the future. */
		dev->kicks_needed++;
		dev->kick_errors = 0;
		/* TODO - device_request_kick (dev); would be more appropriate,
		 * but that doesn't work when called from device context due
		 * to live balls getting bumped */
	}

	/************************************************
	 * Handle kicking out balls
	 ************************************************/
	if (dev->kicks_needed > 0)
	{
		if (dev->actual_count == 0)
		{
			/* Container has fewer balls in it than we
			 * would like */
			dbprintf ("Can't kick when no balls available!\n");
			dev->kicks_needed = 0;
		}
		else if (kickout_locked_p () && !trough_dev_p (dev))
		{
			/* Container ready to kick, but 1 or more
			 * locks are held so we must wait. */
			goto start_update;
		}
		else if (!device_call_boolean_op (dev, kick_request))
		{
			/* Inform other modules that a kick was requested.
			These handlers can return FALSE to delay (but not
			cancel) the kick. */
			goto start_update;
		}
			/* TODO - if multiple devices want to kick at the same time,
			 * they should be staggered a bit.  Another case should be
			 * added here. */
		else
		{
			/* The container is ready to kick */

			/* Mark state as releasing if still idle */
			if (dev->state == DEV_STATE_IDLE)
				dev->state = DEV_STATE_RELEASING;

			/* TODO - keep track of all pending kick attempts.  Use a
			bit variable per device.  If other devices are in the
			process of kicking, wait */

			/* Generate events that a kick attempt is coming */
			callset_invoke (any_kick_attempt);
			device_call_op (dev, kick_attempt);

			/* Pulse the solenoid. */
			sol_request (dev->props->sol);

			/* In timed games, a device kick will pause the game timer.
			 * TODO : this should be a global event that other modules
			 * can catch as well.  Deal with this like we do slowtimers. */
			timed_game_pause (TIME_1S);

			/* We don't know if the kick was successful or not yet, so wait
			and see what happens. */
			goto wait_and_recount;
		}
	}

	/* Just before exiting this task, poll the switches one more time,
	and see if something has changed during the update.  It is important
	that no task context switches take place here, otherwise there would
	be a race condition where a switch closure gets missed. */
	device_recount (dev);
	if (dev->actual_count != dev->previous_count)
		goto start_update;

	task_exit ();
}