#include "config.rh"

#include "paroxysm.rh"

/*
	Breakable object code

	These are really cool entities, but try not to overuse them.
*/
#define SPAWN_GLASS		2
#define SPAWN_METAL		4
#define SPAWN_WOOD		8

.integer gib_caught; // if a gib bounces more than 4 times it's removed

vector (float dm, vector dir) VelocityForRubble =
{
	local vector	v, gib_dir;

	gib_dir = normalize (dir);

	v_x = 90 * gib_dir_x + (random () * 70 - 35);
	v_y = 90 * gib_dir_y + (random () * 70 - 35);
	v_z = 200 + 100 * random ();

	if (dm > -50) {
		v *= 0.9;
	} else if (dm > -200) {
		v *= 2;
	} else {
		v *= 10;
	}

	return v;
};

void () brik_touch =
{
	local float		vol; // randomize the volume so it don't sound like shit

	vol = random ();

	if (@self.velocity == '0 0 0') {
		@self.avelocity = '0 0 0';
		@self.solid = SOLID_NOT;
		@self.touch = NIL;
		@self.think = SUB_Remove;
		@self.nextthink = time + (2 * random());
		return;
	}

	if (@self.gib_caught > 4) {
		remove (@self);
		return;
	}

	// Gib already bounced twice, so remove damage (too easy to get killed)
	if (@self.gib_caught > 1)
		@self.dmg = 0;

	if (@self.dmg) { // do damage if set
		if (other.takedamage) {
			T_Damage (other, @self, @self.owner, @self.dmg);
			remove (@self);
		}
	}

	@self.gib_caught++;

	if (!(@self.cnt))
		return;

	if (vol < 0.3) // mute low volume
		return;

	if (pointcontents(@self.origin) == CONTENT_SOLID) {	// bounce sound
		switch (@self.cnt) {
			case 1:
				sound (@self, CHAN_AUTO, "ambience/brik_hit.wav", vol, ATTN_NORM);
				break;
			case 2:
				sound (@self, CHAN_AUTO, "ambience/brikhit2.wav", vol, ATTN_NORM);
				break;
			case 3:
				sound (@self, CHAN_AUTO, "ambience/methit1.wav", vol, ATTN_NORM);
				break;
			case 4:
				sound (@self, CHAN_AUTO, "ambience/woodhit1.wav", vol, ATTN_NORM);
				break;
			case 6:
				sound (@self, CHAN_AUTO, "ambience/methit2.wav", vol, ATTN_NORM);
				break;
			case 8:
				sound (@self, CHAN_AUTO, "ambience/woodhit2.wav", vol, ATTN_NORM);
				break;
		}
	}
};

void (string gibname, float dm, vector ddir) ThrowRubble =
{
	local entity	new;
	local float		sndrnd;

	new = spawn ();
	sndrnd = random ();

	// new.origin = @self.origin doesnt work because the origin
	// is at world (0,0,0).
	new.origin_x = @self.absmin_x + (random() * @self.size_x);
	new.origin_y = @self.absmin_y + (random() * @self.size_y);
	new.origin_z = @self.absmin_z + (random() * @self.size_z);

	setmodel (new, gibname);
	setsize (new, '0 0 0', '0 0 0');

	if (sndrnd < 0.25)
		new.cnt = 1;
	else if (sndrnd < 0.5)
		new.cnt = 2;

	// No bounce sound for glass since initial sound drags on for a bit
	if (@self.spawnflags & SPAWN_GLASS)
		new.cnt = 0;
	
	if (@self.spawnflags & SPAWN_METAL)
		new.cnt *= 3;	// Play metal bounce on 3 & 6
	
	if (@self.spawnflags & SPAWN_WOOD) {
		new.cnt *= 4;	// Play wood bounce on 4 & 8
		new.skin = 1;	// Change skin to wood if wood gib
	}

	new.velocity = VelocityForRubble (dm, ddir);
	new.movetype = MOVETYPE_BOUNCE;
	new.classname = "rubble";
	new.solid = SOLID_BBOX;
	new.touch = brik_touch;
	new.avelocity_x = random () * 600;
	new.avelocity_y = random () * 600;
	new.avelocity_z = random () * 600;
	new.think = SUB_Remove;
	new.ltime = time;
	new.nextthink = time + 10 + random () * 10;
	new.dmg = @self.dmg;
	new.frame = 0;
	new.flags = 0;
};

/*
	wall_killed

	Called when a wall is destroyed. Throws "gibs" (rubble).
*/
void () wall_killed =
{
	local entity	sndspot;
	local float		rubble_count = 0;
	local string	md1, md2, md3, md4;

	sndspot = spawn();
	sndspot.origin = @self.absmin;
	setorigin (sndspot, sndspot.origin);

	if (@self.spawnflags & SPAWN_GLASS)
		sound (sndspot, CHAN_AUTO, "ambience/glassbrk.wav", 1, ATTN_NORM);
	else if (@self.spawnflags & SPAWN_METAL)
		sound (sndspot, CHAN_AUTO, "ambience/metbrk.wav", 1, ATTN_NORM);
	else if (@self.spawnflags & SPAWN_WOOD)
		sound (sndspot, CHAN_AUTO, "ambience/woodbrk.wav", 1, ATTN_NORM);
	else // New rubble sound
		sound (sndspot, CHAN_AUTO, "ambience/wall01.wav", 1, ATTN_NORM);

	remove (sndspot);

	// determine volume of destroyed wall and throw rubble accordingly
	rubble_count = (@self.size_x * @self.size_y * @self.size_z) / 64000;

	if (rubble_count > 5)
		rubble_count = 6;

	if (@self.spawnflags & SPAWN_GLASS) {
		md4 = md3 = md2 = md1 = "progs/glassrub.md";

		while (rubble_count > -1) {
			@self.dest_x = (random () * 100) - 50;
			@self.dest_y = (random () * 100) - 50;
			@self.dest_z = (random () * 100);

			// This was cut down by 1/5 to deal with packet overflow errors
			ThrowRubble (md1, -100, @self.dest);
			ThrowRubble (md2, -100, @self.dest);
			ThrowRubble (md3, -100, @self.dest);
			ThrowRubble (md4, -100, @self.dest);
			rubble_count--;
		}
	} else {
		if (@self.spawnflags & SPAWN_METAL) {
			md1 = "progs/mwrub1.mdl";
			md2 = "progs/mwrub2.mdl";
			md4 = md3 = "progs/mwrub3.mdl";
		} else if (@self.spawnflags & SPAWN_WOOD) {
			md1 = "progs/mwrub1.mdl";
			md4 = md2 = "progs/mwrub2.mdl";
			md3 = "progs/mwrub3.mdl";
		} else {
			md1 = "progs/rubble1.mdl";
			md4 = md2 = "progs/rubble2.mdl";
			md3 = "progs/rubble3.mdl";
		}

		while (rubble_count > -1) {
			@self.dest_x = (random () * 100) - 50;
			@self.dest_y = (random () * 100) - 50;
			@self.dest_z = (random () * 100);

			ThrowRubble (md1, @self.health, @self.dest);
			ThrowRubble (md2, @self.health, @self.dest);
			ThrowRubble (md3, @self.health, @self.dest);
			ThrowRubble (md4, @self.health, @self.dest);
			rubble_count--;
		}
	}
	activator = @self;

	SUB_UseTargets ();
     
	@self.no_obj = TRUE; // mine fix - mines will detonate if spawnmaster.no_obj = TRUE (blown up)
	remove (@self);
};

void() wall_pain =
{
	if (@self.health > 0)
		@self.health = @self.max_health;
};

void() wall_use =
{
	@self.health = -100;
	@self.dest_x = (random () * 10) - 5;
	@self.dest_y = (random () * 10) - 5;
	@self.dest_z = (random () * 10);
	wall_killed ();
};

/*QUAKED exploding_wall
When the exploding wall is shot, it "gibs" into rubble.
Can also be triggered to explode.

"target"	all entities with a matching targetname will be used when killed
"health"	the amount of damage needed to destroy the wall instead of touched
"dmg"		damage caused when hit by a gib

New Spawnflags added for PAROXYSM:

SPAWN_GLASS - glass explosion

SPAWN_METAL - metal shrapnel

SPAWN_WOOD - wood splintering

- no spawnflags is concrete rubble

Although it is possible to combine different types of explosions on one object,
it is not recommended. You can easily get overflow errors on large objects AND
since wood and metal share a gib model, no metal skins will be used if the
wood spawnflag is set.
*/
void() exploding_wall =
{
	setmodel (@self, @self.model);
	
	// New precache routine
	
	precache_sound("zombie/z_hit.wav"); // for damage
	
	if (@self.spawnflags & SPAWN_GLASS) {
		precache_model("progs/glassrub.mdl");
		precache_sound("ambience/glassbrk.wav");
	} else if (@self.spawnflags & SPAWN_METAL) {
		precache_model("progs/mwrub1.mdl");
		precache_model("progs/mwrub2.mdl");
		precache_model("progs/mwrub3.mdl");
		precache_sound("ambience/metbrk.wav");
		precache_sound("ambience/methit1.wav");
		precache_sound("ambience/methit2.wav");
	} else if (@self.spawnflags & SPAWN_WOOD) {
		precache_model("progs/mwrub1.mdl");
		precache_model("progs/mwrub2.mdl");
		precache_model("progs/mwrub3.mdl");
		precache_sound("ambience/woodbrk.wav");
		precache_sound("ambience/woodhit1.wav");
		precache_sound("ambience/woodhit2.wav");
	} else { // precache concrete
		precache_model("progs/rubble1.mdl");
		precache_model("progs/rubble2.mdl");
		precache_model("progs/rubble3.mdl");
		precache_sound("ambience/wall01.wav");
		precache_sound("ambience/brik_hit.wav");
		precache_sound("ambience/brikhit2.wav");
	}

	@self.solid = SOLID_BBOX;
	@self.movetype = MOVETYPE_NONE;
	
	// POX v1.2 - default gib damage to 1
	if (!@self.dmg)
		@self.dmg = 1;
	
	@self.nobleed = TRUE;

	if (@self.health) {
		@self.max_health = @self.health;
		@self.th_die = wall_killed;
		@self.takedamage = DAMAGE_YES;
	} else {
		@self.max_health = 100;
		@self.th_die = wall_killed;
		@self.takedamage = DAMAGE_YES;
	}

	@self.th_pain = wall_pain;

	if (@self.targetname) {
		@self.use = wall_use;
		@self.max_health = 10000;
	}
};
