first commit
This commit is contained in:
322
mod_slipgate/source/server/breakable.qc
Normal file
322
mod_slipgate/source/server/breakable.qc
Normal file
@@ -0,0 +1,322 @@
|
||||
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;
|
||||
};
|
||||
Reference in New Issue
Block a user