def title	"KRChipSFX"
def version	"1.0.0"
def description	"Kobo Redux Chip Sound Theme - Sound Effects"
def author	"David Olofson"
def copyright	"Copyright 2016-2017 David Olofson"
def license	"GPL"
def a2sversion	"1.9.1"


  /////////////////////////////////////////////////////////////////////////////
 // Designing sound themes for Kobo Redux
///////////////////////////////////////////////////////////////////////////////
//
// Overview
//----------
// Each game object (enemy, bullet, explosion, ...) has four hardwired sound
// slots; one continuous sound effect that runs during the lifetime of the
// object, and three one-shot event slots; launch, damage, and death. All slots
// are wired to the game logic, but they're all optional. Sound themes should
// just leave undesired slots undefined.
//
// All slot programs are expected to take the same arguments; (pP pV pX), which
// are expected to initialize the pitch, volume, and horizontal pan position.
// (See below for more on positional audio.)
//
//	Examples:
//		S_CORE		Base core continuous sound with damage response
//		S_ROCK_LAUNCH	Rock launch one-shot sound effect
//		S_ROCK_DAMAGE	Rock damage (hit) one-shot sound effect
//		S_ROCK_DEATH	Rock death (explosion) one-shot sound effect
//
// NOTE:
//	For theme development purposes, it's recommended to set a sensible
//	default value for the pV argument, but this is not strictly required,
//	as the game engine will always specify all arguments.
//
//
// Continuous positional sound effects
//-------------------------------------
// The continuous sounds effects are 2D positional, and are expected to respond
// to certain voice messages while playing. They are started with a2_Start(),
// and remain attached until the object is destroyed, whereby message 1() is
// passed, after which the voice is detached. Unlike one-shot 
//
//	Messages:
//		1()
//			Stop the sound. Normally implies death.
//
//		2(Damage)
//			Object has taken damage. The argument specifies the
//			amount.
//
//		3(npP npV npX Dur)
//			Positional audio update. pP is the new pitch, npV is
//			the new volume, and npX is the new horizontal pan
//			position.
//
//			The npP argument is intended for Doppler effects, and
//			is a 1.0/octave linear pitch offset from the normal
//			pitch of the sound effect. (Not yet implemented in the
//			game.)
//
//			The simplest way of implementing npV and npX is to use
//			a 'panmix' unit as the final stage in the voice
//			structure, and apply the arguments directly to its
//			'vol' and 'pan' registers.
//
//			Changes are expected to be linearly ramped over the
//			time specified via the 'Dur' argument.
//
//
// Extra sound effect slots
//--------------------------
// Some objects also have additional sound slots, named S_<object>_<x>, where
// <x> is a descriptive name of the slot. These may have nonstandard arguments
// and message handlers, though they will typically match the behavior of
// either continuous or one-shot sounds, as described above.
//
//	Extra enemy sound slots:
//
//		Continuous positional sounds:
//			S_BOMB1_TRIG		Bomb 1 trigger warning bleep
//			S_BOMB2_TRIG		Bomb 2 trigger warning bleep
//
//		One-shot sounds:
//			S_BOMB1_DETONATE	Bomb 1 detonation
//			S_BOMB2_DETONATE	Bomb 2 detonation
//			S_ENEMY_M1_BAILOUT	Enemy M1 final bailout spawn
//			S_ENEMY_M2_BAILOUT	Enemy M2 final bailout spawn
//			S_ENEMY_M3_BAILOUT	Enemy M3 final bailout spawn
//			S_ENEMY_M4_BAILOUT	Enemy M4 final bailout spawn
//
//	Other extra sound slots:
//
//		One-shot sounds:
//			S_NO_DAMAGE		Deflect "clank" for base pipes
//
//
// Player ship sound effects
//---------------------------
// The player ship is (as of now) not based on the enemy model, and has its own
// sound interface. It is, however, based on the same logic as the enemy sound
// effects, so the same concepts still apply.
//
//	Player ship sound effect slots:
//		S_PLAYER_DAMAGE		One-shot damage sound
//		S_PLAYER_DEATH		One-shot player death sound
//		S_PLAYER_GUN		Player gun sound program (nonstandard)
//
// The most interesting part here is S_PLAYER_GUN, which is actually a single
// program implementing a number of related sound effects. The program takes
// the same (pP pV pX) arguments as other continuous sound effects, but it does
// NOT implement the usual positional update messages. It will typically start
// silent, and the sound effects are then controlled via voice messages.
//
//	S_PLAYER_GUN messages:
//		2()	Fire primary weapon
//		3(Ch)	Secondary weapon charge "blipp"; Ch is current level.
//		4(Ch)	Fire secondary (charged) weapon
//
//
// TODO
//------
// Document the mixer group programs, songs, and UI sound effects. For now,
// look at the examples included with this theme.
//
//	Relevant slots:
//		Mixer groups:
//			S_G_MASTER	Master section (parent of all groups)
//			S_G_UI		User interface sound effect group
//			S_G_SFX		Ingame sound effects group
//			S_G_MUSIC	Ingame music group
//			S_G_TITLE	Title/UI music group
//
//		Music:
//			S_OAJINGLE	Olofson Arcade jingle
//			S_TITLESONG	Game title song
//			S_INGAMESONG1	Ingame track for region 1
//			S_INGAMESONG2	Ingame track for region 2
//			S_INGAMESONG3	Ingame track for region 3
//			S_INGAMESONG4	Ingame track for region 4
//			S_INGAMESONG5	Ingame track for region 5
//
///////////////////////////////////////////////////////////////////////////////


 // Common sound effects
///////////////////////////////////////////////////////////////////////////////

Damage(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	+tr (pP + 1 + rand .5)
	d rand 50
	phase 0
	@a .4
	@p .5
	-p 2.1; a .2;		d 30
	@a .1; @p (rand .3);	d 10
	a 0; @p (2 + rand .3);	d 10
	w noise; @p 3
	a .1;			d 10
	a .05;			d 50
	a 0;			d 150
}

NodeExplo(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	+tr pP
	@a .5
	@p (1 + rand .5)
	-p 3.5;			d 50
	@p (rand .3)
	5 {
		w noise
		-p .2;	*a .9;	d 10
		w square
		-p .2;	*a .9;	d 10
	}
	while a > .01 {
		w noise
		-p .02;	*a .95;	d 10
		w square
		-p .02;	*a .95;	d 10
	}
	a 0;			d 10
}

EnemyExplo(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	+tr pP
	@a .7; @p (.5 + rand 1)
	-p 2;			d 20
	w noise; @p (1.5 + rand 1)
	-p 3; *a .5;		d 50
	*a .3; +p 1.5;		d 10
	*a .5;			d 50
	*a .5;			d 50
	@p rand 1
	a .05;			d 50
	*a .3;			d (50 + rand 100)
	a 0;			d (100 + rand 300)
}


 // Enemy bullets
///////////////////////////////////////////////////////////////////////////////

export S_BULLET1_LAUNCH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w pulse1
	+tr (pP - 1.1); @p 0
	+a .3; +p .02;		d 20
	-a .15; -p .03;		d 30
	@a .1; w noise; p 7;	d 10
	@a .02;	a 0;		d 150
}

export S_BULLET2_LAUNCH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w pulse2
	+tr (pP - 1.6); @p 0
	+a .3; +p .02;		d 20
	-a .1; -p .04;		d 40
	@a .15; w noise; p 7.5;	d 10
	@a .035; a 0;		d 150
}

export S_BULLET3_LAUNCH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w pulse4
	+tr (pP - 2); @p 0
	+a .4; +p .04;		d 40
	-a .3; -p .06;		d 60
	@a .25; w noise; p 8;	d 10
	@a .04; p 7; a .04;	d 50
	a 0;			d 150
}


 // Rocks
///////////////////////////////////////////////////////////////////////////////

export S_ROCK_LAUNCH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w noise
	+tr pP; @p 0
	+a .15; +p 1;		d 100
	5 {
		*a .25
		@p 1
		-p .2;		d 200
	}
	a 0;			d 200
}

export S_ROCK_DAMAGE(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w triangle
	+tr (pP + 3 + rand .5)
	d rand 50
	phase 0
	@a .5;			d 10
	a .5; @p -3; -p .8;	d 10
	w triangle; -p .8;	d 10
	a 0;			d 10

	@p 6; a .1;		d 10
	w noise; @p (rand .5 - 1)
	a 0;			d 50
}

export S_ROCK_DEATH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w noise
	+tr pP
	@p 3
	3 {
		@p (rand 3)
		@a (.3 + rand .5)
		a 0
		d (10 + rand 20)
	}
	w square; a 1; -tr 3; @p 4
	10 {
		-p (.3 + rand .5)
		*a .9
		d 10
	}
	w noise; @a 0; @p 4
	a .3; 			d 100
	*a .25;			d 200
	*a .25;			d 400
	a 0;			d 800
}


 // Ring
///////////////////////////////////////////////////////////////////////////////

export S_RING_LAUNCH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w triangle
	+tr (pP - 1); @p 0
	+a 1; +p 2;		d 100
	5 {
		*a .25
		@p 1
		+p 1;		d 100
	}
	a 0;			d 100
}

export S_RING_DEATH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w noise
	+tr (pP - 1); @p 3
	a .5
	a 0; +p .7;				d 50
	a .5
	5 {
		*a .25
		@p 1
		10 {
			!tr0 tr
			if (rand 1 > .5) {
				w triangle
			} else {
				w noise
				+tr 2
			}
			+p .1; set p;		d 10
			tr tr0
		}
	}
	a 0;					d 10
}


 // Bomb 1
///////////////////////////////////////////////////////////////////////////////

export S_BOMB1_LAUNCH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w triangle
	+tr pP
	@a .2
	@p 2; -p 2.1;		d 60
	w noise; @a .1; @p 7;	d 20
	w triangle; @p -2.5; a 1
	+p 2;			d 100
	w noise; @a .05; @p 3;	d 20
	w triangle; @p -2.5; a 1
	5 {
		*a .25
		@p -1
		-p 1;		d 200
	}
	a 0;			d 200
}

export def S_BOMB1_DEATH EnemyExplo

export S_BOMB1_TRIG(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w triangle
	a .1
	!playing 1
	while playing {
		3 {
			@p 40n;		d 10
			@p 45n;		d 10
		}
	}
	1() {
		playing 0
	}
	2(Dmg) { }
	3(npP npV npX Dur) {
		vol npV; pan npX; ramp Dur
	}
}

export S_BOMB1_DETONATE(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	+tr pP
	w square
	+tr pP
	@a .5
	@p 2
	-p 4.9;		d 70
	w noise; @p 2; @a .3
	while a > .01 {
		*a .93;		d 10
	}
	a 0;		d 100
}


 // Bomb 2
///////////////////////////////////////////////////////////////////////////////

export def S_BOMB2_LAUNCH	S_BOMB1_LAUNCH
export def S_BOMB2_DEATH	EnemyExplo

export S_BOMB2_TRIG(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w triangle
	a .1
	!playing 1
	while playing {
		3 {
			@p 38n;		d 10
			@p 47n;		d 10
		}
	}
	1() {
		playing 0
	}
	2(Dmg) { }
	3(npP npV npX Dur) {
		vol npV; pan npX; ramp Dur
	}
}

export S_BOMB2_DETONATE(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	+tr pP
	w square
	+tr pP
	@a .7
	@p 2.5
	-p 5.6;			d 70
	w noise; @p 1.5; @a .5
	while a > .01 {
		*a .93;		d 10
	}
	a 0;			d 100
}


 // Explosions
///////////////////////////////////////////////////////////////////////////////

// (No sound effects)


 // Base cannon
///////////////////////////////////////////////////////////////////////////////

export def S_CANNON_DAMAGE	Damage
export def S_CANNON_DEATH	NodeExplo


 // Base core
///////////////////////////////////////////////////////////////////////////////

export S_CORE(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	-tr (2 - pP + rand .2)
	!pf (.77 + rand .01)
	def A0 .1
	a 0

	// Wrrrrrr...
	!running 1
	while running {
		!pd (p2d (p + tr) * pf)
		+a (A0 - a * .1)
		+tr .7; *p .98; set p;		d pd
		-tr .7; *p .98; set p;		d pd
	}

	// Destruction!
	!ps p	// (Save)

	//	Breakage
	w noise; @a .7;	@p 7
	-p 3;					d 30

	//	Thud
	w square; @p 2
	-p .3;					d 30

	p ps	// (Restore)

	//	Over-rev
	@a (A0 * 2)
	!revup (.04 + rand .01)
	50 {
		+a .005
		!pd (p2d (p + tr) * pf)
		+tr .7; +p revup; set p;	d pd
		-tr .7; +p revup; set p;	d pd
		*revup .95
	}

	//	Explosion
	@a 1
	@p 3
	-p 2.5;					d 50
	w noise; a .5; @p 4
	while a > .001 {
		*p .99; *a .95;			d 20
	}
	a 0;					d 10

	// Stop
	1() {
		running 0
	}

	// Damage
	2(Dmg) {
		+p Dmg
		+a Dmg
		if (p > 1) {
			p 1
		}
		if (a > .5) {
			a .5
		}
	}

	// Positional update
	3(npP npV npX Dur) {
		vol npV; pan npX; ramp Dur
	}
}


 // Base pipe, inwards chain explosion
///////////////////////////////////////////////////////////////////////////////

export S_PIPEIN(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w triangle; a .2; +tr (pP - 3)

	!PE 5
	!running 1
	while running or (a > .01) {
		*a .97; p (PE + rand 2);	d 5
		*PE .7
	}
	a 0;					d 10

	1()	{
		running 0
	}

	2(Int)	{
		*Int .5
		a (Int + .5); ramp a 10
		PE (Int + 4)
	}

	3(npP npV npX Dur) {
		vol npV; pan npX; ramp Dur
	}
}


 // Base pipe, outwards chain explosion
///////////////////////////////////////////////////////////////////////////////

export def S_PIPEOUT		S_PIPEIN


 // Enemies 1-7
///////////////////////////////////////////////////////////////////////////////

GenericLaunch(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w noise
	+tr (pP + 2); @p 0
	+a .15; +p 1;		d 100
	5 {
		*a .25
		@p 1
		+p .2;		d 200
	}
	a 0;			d 200
}

export def S_ENEMY1_LAUNCH	GenericLaunch
export def S_ENEMY2_LAUNCH	GenericLaunch
export def S_ENEMY3_LAUNCH	GenericLaunch
export def S_ENEMY4_LAUNCH	GenericLaunch
export def S_ENEMY5_LAUNCH	GenericLaunch
export def S_ENEMY6_LAUNCH	GenericLaunch
export def S_ENEMY7_LAUNCH	GenericLaunch

export def S_ENEMY1_DAMAGE 	Damage
export def S_ENEMY2_DAMAGE 	Damage
export def S_ENEMY3_DAMAGE 	Damage
export def S_ENEMY4_DAMAGE 	Damage
export def S_ENEMY5_DAMAGE 	Damage
export def S_ENEMY6_DAMAGE 	Damage
export def S_ENEMY7_DAMAGE 	Damage

export def S_ENEMY1_DEATH 	EnemyExplo
export def S_ENEMY2_DEATH 	EnemyExplo
export def S_ENEMY3_DEATH 	EnemyExplo
export def S_ENEMY4_DEATH 	EnemyExplo
export def S_ENEMY5_DEATH 	EnemyExplo
export def S_ENEMY6_DEATH 	EnemyExplo
export def S_ENEMY7_DEATH 	EnemyExplo


 // Enemies M1-M4
///////////////////////////////////////////////////////////////////////////////

export BigShipReactor(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set

	def A0 .3
	def TR -3

	!tr0 (tr + pP + rand .2)
	tr (tr0 + TR)
	!pf (.51 + rand .01)
	!damage_amount 0
	a 0

.resume
	// Engines
	w square
	for {
		!pd (p2d (p + tr) * pf)
		+a (A0 - a * .1)
		+tr 1; *p .99; set p;	d pd
		-tr 1; *p .99; set p;	d pd
	}

.damage
	!ps p
	tr (tr0 + TR)
	@p (2 + damage_amount)
	a damage_amount
	-p 2.5;			d 50
	a A0;			d 10
	@p (damage_amount + ps)
	if (p > 2) p 2
	jump resume

.death
	w square
	tr tr0
	@a .7
	@p 2
	-p 2.5;			d 50
	-p 1;			d 100
	w noise; @p -2
	+p 2;			d 100
	15 {
		-p .05; *a .8;	d 100
	}
	a 0;			d 100

	// Stop
	1() {
		force death
	}

	// Damage
	2(Dmg) {
		damage_amount (Dmg * .5 + .5)
		if (damage_amount > 2) {
			damage_amount 2
		}
		force damage
	}

	// Positional update
	3(npP npV npX Dur) {
		vol npV; pan npX; ramp Dur
	}
}

export def S_ENEMY_M1		BigShipReactor
export def S_ENEMY_M2		BigShipReactor
export def S_ENEMY_M3		BigShipReactor
export def S_ENEMY_M4		BigShipReactor

BigShipBailout(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w pulse10
	+tr (pP - 3); @p 0
	+a 1; +p .1;		d 100
	-a 1; -p .1;		d 100
	@a .5; w noise; @p 6;	d 10
	@a .1; @p 8
	*a .25;			d 100
	a 0;			d 100
}

export def S_ENEMY_M1_BAILOUT	BigShipBailout
export def S_ENEMY_M2_BAILOUT	BigShipBailout
export def S_ENEMY_M3_BAILOUT	BigShipBailout
export def S_ENEMY_M4_BAILOUT	BigShipBailout


 // Player ship sound effects
///////////////////////////////////////////////////////////////////////////////

export S_PLAYER_DAMAGE(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	+tr (pP + 1 + rand .5)
	d rand 50
	phase 0
	@a 1
	-p 3; *a .5;	d 30
	-p .6;		d 20
	a 0;		d 10
	w noise; @p 2.3
	a .5;		d 10
	a .2;		d 50
	a 0;		d 200
}

export S_PLAYER_DEATH(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	+tr pP
	@a .5
	@p 2
	-p 5;			d 100
	@p 2
	5 {
		-tr .2; @p (rand .5)
		*a .95
		d 10
	}
	while a > .001 {
		-tr .01; @p (rand 1)
		*a .98
		d 10
	}
	a 0;			d 10
}

ChargeBlipp(pP pV=1 pX Charge=1)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	a .2; w saw; @p (Charge * 2);	d 2
	*a .5; -p .5;			d 5
	a 0;				d 10
}

FireCharged(pP pV=1 pX Charge=1)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	!tr0 (tr + pP - 4)
	tr tr0
	a (Charge * .5 + .5); set a; w saw; @p (5 + Charge)
	20 {
		tr (tr0 + rand 1 - .5)
		*p .96
		d 5
	}
	while a > .05 {
		tr (tr0 + rand 1 - .5)
		*p .98
		-a .01
		d 5
	}
	a 0; d 100
}

export S_PLAYER_GUN(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w saw
	+tr pP

	sleep	// Hold here until we start firing!

.retrig
	@a .15
	@p 2
	*p .03; *a .1;		d 100

	// Recharge (aborted if retrigged)
	@p 1
	15 {
		+a .005
		+p .9;		d 10
		-p .85;		d 10
	}
	20 {
		+p .7;		d 10
		-p .65;		d 10
	}
	a 0;			d 10

	2() {
		force retrig
	}

	3(Ch) {
		ChargeBlipp pP pV pX Ch
	}

	4(Ch) {
		FireCharged pP pV pX Ch
	}
}

export S_PLAYER_FIRE_DENIED(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square

	a .05; +p 3;	d 5
	3 {
		+p 1;	set p
			d 5
		-p 1;	set p
			d 10
	}
	a 0;		d 5
}

export S_PLAYER_SHIELD(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set

	!damage_amount 0
	!S 0
	!A 1
	@a .25

	while (S > .001 or A) {
		+S (A - S * .1)
		w pulse25
		+a (A * .5 + .5 * .25 + damage_amount - a * .1)
		@p (rand 5 * damage_amount + 2)
		p (damage_amount * 3)
		*damage_amount .8
		!D (damage_amount * 5 + 1)
		d D

		w triangle
		-p 2.1
		d (S * 15 + 4 - D)
	}

	a 0;	d 10

	// Stop
	1() {
		A 0
	}

	// Damage
	2(Dmg) {
		damage_amount (Dmg * .5 + .5)
		if (damage_amount > 2) {
			damage_amount 2
		}
	}

	// Positional update
	3(npP npV npX Dur) {
		vol npV; pan npX; ramp Dur
	}
}


 // Other sound effects
///////////////////////////////////////////////////////////////////////////////

export S_NO_DAMAGE(pP pV=1 pX)
{
	struct { wtosc; panmix }
	pan pX; vol pV; set
	w square
	+tr pP
	@a .1; @p (1 + rand .3);	d 5
	a .03; @p (rand .5 - 1);	d 10
	a 0; @p (3 + rand .3);		d 30
}
