Files
quakemapping/mod_slipgate/source/server/breakable.qc
2019-12-30 17:23:05 +01:00

323 lines
7.3 KiB
Plaintext

static enumflags { EXPLODE, NO_EXPLOSION_SPRITE, NO_EXPLOSION_SOUND, SPAWN_SMOKE };
/*==========
breakable_pain
==========*/
static void(entity attacker, float damage) breakable_pain =
{
// play impact sound if set
if (self.noise2 != "")
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
};
/*==========
breakable_think
==========*/
static void() breakable_think =
{
// hack to drop to ground if something below us was removed
if (self.flags & FL_ONGROUND)
self.flags = self.flags - FL_ONGROUND;
// fade out when self.attack_finished is up
if (time > self.attack_finished)
{
if (self.alpha == 0)
self.alpha = 1;
self.alpha = self.alpha - 0.1;
if (self.alpha <= 0)
{
remove(self);
return;
}
}
self.think = breakable_think;
self.nextthink = time + 0.1;
};
/*==========
breakable_touch
==========*/
static void() breakable_touch =
{
if (other != world)
return;
if (self.count)
return;
if (random() < 0.5)
return;
self.count = 1;
if (self.noise2 != "")
sound(self, CHAN_VOICE, self.noise2, 0.5, ATTN_IDLE);
};
/*==========
breakable_smoke
==========*/
static void(vector org) breakable_smoke =
{
entity smoke = spawn();
smoke.classname = "smoke";
smoke.solid = SOLID_NOT;
smoke.movetype = MOVETYPE_TOSS;
setmodel(smoke, "progs/smoke.mdl");
setorigin(smoke, org);
setsize(smoke, '0 0 0', '0 0 0');
smoke.velocity = [crandom()*200, crandom()*200, random()*100 + 100];
smoke.think = SUB_Remove;
smoke.nextthink = time + 1;
};
/*==========
breakable_spawn_debris
==========*/
static void(vector org, vector sz, vector dir) breakable_spawn_debris =
{
entity debris = spawn();
debris.classname = "debris";
debris.solid = SOLID_TRIGGER;
debris.movetype = MOVETYPE_BOUNCE;
setorigin(debris, [org.x + random() * sz.x, org.y + random() * sz.y, org.z + random() * sz.z]);
float r = random();
if (r < 0.33)
setmodel(debris, self.mdl1);
else if (r < 0.66)
setmodel(debris, self.mdl2);
else
setmodel(debris, self.mdl3);
// spawn some smoke particles
if (self.spawnflags & SPAWN_SMOKE)
if (random() < 0.5)
breakable_smoke(debris.origin);
debris.angles_y = random() * 360;
debris.velocity = dir * (50 + random() * 50);
debris.velocity_z = 50 + random() * 50;
if (self.health < -40)
debris.velocity = debris.velocity * 2;
debris.avelocity = randomvec() * 100;
debris.noise2 = self.noise2;
debris.touch = breakable_touch;
debris.think = breakable_think;
debris.nextthink = time + 0.1;
debris.attack_finished = time + 10 + random() * 10;
};
/*==========
breakable_explode
==========*/
static void() breakable_explode =
{
setorigin(self, realorigin(self)); // fix bmodel origin
if (self.dmg > 0)
RadiusDamage (self, self, self.dmg, world);
if (self.spawnflags & NO_EXPLOSION_SOUND)
{
// vanilla hack to get explosion particles with no sound/light
particle (self.origin, '0 0 0', 0, 255);
}
else
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
if (self.spawnflags & NO_EXPLOSION_SPRITE)
remove(self);
else
BecomeExplosion ();
};
/*==========
breakable_break
==========*/
static void(entity inflictor) breakable_break =
{
self.takedamage = DAMAGE_NO;
self.use = SUB_Null;
// play sound, if set
if (self.noise1 != "")
sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
// turn shadow off, supported by ericw-tools
if (self.switchshadstyle >= 32)
lightstyle(self.switchshadstyle, "m");
// the debris moves away from the direction of attack
// if movedir is set, this always overrides the direction
while (self.count > 0)
{
vector dir;
if (self.movedir)
dir = self.movedir;
else
{
if (inflictor == world)
dir = randomvec();
else
dir = normalize((self.absmin + self.absmax) * 0.5 - inflictor.origin);
}
breakable_spawn_debris(self.absmin, self.size, dir);
self.count = self.count - 1;
}
if (self.spawnflags & EXPLODE)
self.think = breakable_explode;
else
self.think = SUB_Remove;
self.nextthink = self.ltime + 0.01; // use ltime because it's MOVETYPE_PUSH
// fire targets
activator = self.enemy;
UseTargets();
};
/*==========
breakable_die
==========*/
static void(entity inflictor, entity attacker) breakable_die =
{
self.enemy = attacker;
breakable_break(inflictor);
};
/*==========
breakable_use
==========*/
static void() breakable_use =
{
self.enemy = activator;
breakable_break(world);
};
/*QUAKED func_breakable (0 .5 .8) ? EXPLODE NO_EXPLOSION_SPRITE NO_EXPLOSION_SOUND SPAWN_SMOKE X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Breakable brush model
Spawnflags:
EXPLODE - will explode upon destruction. Set the dmg key to the force of the explosion.
You can set dmg to 0 for just the explosion effects.
NO_EXPLOSION_SPRITE - don't show explosion sprite.
NO_EXPLOSION_SOUND - don't make explosion sound or light.
SPAWN_SMOKE - will spawn some additional smoke upon destuction
Keys:
"style" "n"
Preset style, 1=base crates, 2=stone/brick
Sets debris model, particle color and sounds automatically
If mdl1-3, noise or colour are set they will override the preset
"mdl1", "mdl2", "mdl3" "name"
custom models for debris chunks
"color" "n"
particle color for damage, range 0-254 (from palette)
"noise1", "noise2" "name"
custom sound for break / damage
"health" "n"
damage required to destroy. default 30.
"targetname" "name"
if set, the breakable must be triggered to destroy it
"count" "n"
number of pieces of debris to spawn. default 8.
"angle" "n"
If set, overrides the direction debris moves in. Use -1 and -2 for up/down. Use 360 for a yaw of 0.
"dmg" "n"
Amount of explosive damage to deal. Default 60.
*/
void() func_breakable =
{
// turn shadow on, supported by ericw-tools
if (self.switchshadstyle >= 32)
lightstyle(self.switchshadstyle, "a");
// pre-set styles
// 1 - base crate
if (self.style == 1)
{
if (!self.mdl1)
self.mdl1 = "maps/crate1.bsp";
if (!self.mdl2)
self.mdl2 = "maps/crate2.bsp";
if (!self.mdl3)
self.mdl3 = "maps/crate3.bsp";
if (!self.noise1)
self.noise1 = "break/metbrk.wav";
if (!self.noise2)
self.noise2 = "break/methit.wav";
if (!self.colour)
self.colour = 24;
}
// 2 - stone/brick
else if (self.style == 2)
{
if (!self.mdl1)
self.mdl1 = "maps/brick1.bsp";
if (!self.mdl2)
self.mdl2 = "maps/brick2.bsp";
if (!self.mdl3)
self.mdl3 = "maps/brick3.bsp";
if (!self.noise1)
self.noise1 = "break/stonebrk.wav";
if (!self.noise2)
self.noise2 = "break/stonehit.wav";
if (!self.colour)
self.colour = 16;
}
if (!self.mdl1 || !self.mdl2 || !self.mdl3)
{
objerror("mdl1, mdl2 or mdl3 not set\n");
remove(self);
return;
}
precache_model(self.mdl1);
precache_model(self.mdl2);
precache_model(self.mdl3);
// destruction and impact noises - optional
if (self.noise1 != "")
precache_sound(self.noise1);
if (self.noise2 != "")
precache_sound(self.noise2);
SetPositiveDefault(count, 8);
SetPositiveDefault(dmg, 8);
if (self.angles)
SetMovedir();
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
setmodel (self, self.model);
// shootable, not triggered
if (!self.targetname)
{
SetPositiveDefault(health, 30);
self.takedamage = DAMAGE_YES;
self.th_pain = breakable_pain;
self.th_die = breakable_die;
}
else
self.use = breakable_use;
};