/*
* KEEPY-UPPY
*
* An AUDIO-ONLY game by Dan Stowell <danstowell@users.sourceforge.net> (C) 2005
*
*  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
*
* This game is inspired by the work of "One Switch"
* http://www.oneswitch.org.uk/ - developing games and controllers
* to accommodate various types of disability, including...
* audio-only games.
*
* RULES:
*  You are kicking a football into the air. You can hear it fly
*  up into the air and down again, and when it comes down you
*  must press SPACE to kick it up again.
*
*  The ball may move slightly towards the left or right so you
*  may need to move left or right using the cursor keys to
*  keep within range of the ball (wear headphones for best
*  control!)
*
*  The aim is to kick it up as many times as you can.
*
*
*/

// For voice-over, you need the say-Quark installed (unix/macOs only)

Quarks.install("say");



s.boot; // First make sure the server is on

// Then send it the SynthDefs we need
(
SynthDef(\kuball, { |amp=0.5, pan=0, freq=100|
	Out.ar(0, Pan2.ar(amp * 2 * (BPF.ar(WhiteNoise.ar, freq, 0.1)*10).clip2 * SinOsc.ar(4.5), pan))
}).add;

SynthDef(\gameover, { Out.ar(0, SinOsc.ar(
	Line.kr(200, 100, 1.0, doneAction:0),
	0,
	EnvGen.kr(Env([0.3, 0.2, 0.2, 0], [0.1, 0.8, 0.1]), 1, doneAction:2)
).dup(2))}).add;

SynthDef(\whackit, {Out.ar(0, SinOsc.ar(74, 0.5pi,
	EnvGen.kr(Env.perc(0, 0.05), doneAction:2)).dup(2))}).add;

);

// Now define the game (won't run until we run the last line in this file)
(
~game = {

	var whacks, xpos, ypos, xvel, yvel, whack, dogravity, framedur, doc, whackdisabled, whackspacing;

	var selector = if(\Say.asClass.notNil) { \say } { \postln };


	whacks = 0;
	xpos   = 0;
	ypos   = 0;
	xvel   = 0;
	yvel   = 10;
	framedur = 0.1; // The amount of time between two "frames" of calculation
	whackdisabled = false;
	whackspacing = 0.3; // The amount of time you must wait between whacks

	whack = {
		if(ypos < 20,
			{
				if(xpos.abs < 1,
					{
						if((yvel < 0) && (whackdisabled==false),
							{
								yvel = rrand(6.0, 14.0);
								ypos = max(0.1, ypos);
								xvel = 0.1.bilinrand;
								Synth(\whackit);
								whackdisabled = true;
								Task({whackspacing.wait; whackdisabled = false}).play;
								whacks = whacks + 1;
						});
				});
		});
	}; // End of whack function

	dogravity = {
		yvel = yvel - 1.0;
		ypos = ypos + yvel;
		xpos = xpos + xvel;
	};

	Task({
		var kuball;

		kuball = Synth(\kuball);

		// Set up keyboard handlers
		{
			doc = Window("Use LEFT and RIGHT arrows and SPACEBAR");
			doc.front;
		}.defer;

		0.1.wait;
		doc.view.keyDownAction_({arg ...args;
			switch(args[3],
				32   , {whack.value}, // space
				63234, {xpos = xpos + 0.1}, // left arrow
				63235, {xpos = xpos - 0.1} // right arrow
			);
		});

		// This is the loop which runs the game
		while({ypos >= 0},
			{
				dogravity.value;
				kuball.set(\amp, 0.5 * (1.0/max(1.0, ypos)),
					\pan, max(-1.0, min(1.0, xpos)),
					\freq, 200 + max(0, ypos * 10));
				framedur.wait;
		});

		// Destroy keyboard handlers
		doc.view.keyDownAction_(nil);
		kuball.free;

		// Run the end-of-game feedback etc
		Synth(\gameover);
		1.5.wait;
		AppClock.sched(0.0, {doc.close;});
		switch(whacks,
			0, {("You didn't hit the ball - sorry").perform(selector) },
			1, {("You hit the ball once").perform(selector) },
			2, {("You hit the ball twice").perform(selector) },
			3, {("You hit the ball 3 times").perform(selector) },
			4, {("You hit the ball 4 times - well done").perform(selector) },
			5, {("You hit the ball 5 times - well done").perform(selector) },
			{("You hit the ball "+whacks+" times - well done indeed!").perform(selector) }
		);

	}).play(AppClock);


}
)
~game.value; // Press Enter to play!
