xmen/LITENING.c
2005-09-22 00:00:00 +00:00

311 lines
7.9 KiB
C

/* Begin Xmen
Lightning revision 2
-cl2-
Revisions:
2: Added some safeguards to make lightning work right
Fixed error messages
Files involved:
litening.qc (this file)
How to implement in a map file:
Place a info_lightning somewhere. Give it a style.
Place other lightning_waypoints all with the same style as startpoint.
String 'em together via 'target' and 'targetname' and voila... lightning. I hope.
"style" : light style it affects (12-31)
"waitmin" : min. time between flashes (default = 3)
"waitmax" : max. time between flashes (default = 10)
"spawnflags" : if 1, bolt will randomly fork off at junctions (default = 0)
"distance" : how long the forks can be (default = 64)
Does looking at other people's code give you a headache, too? ;)
*/
void() lightning_trigger;
float(entity e1, entity e2, float dam) DoABolt =
{
// traceline(e1.origin, e2.origin, FALSE, world);
FillBetweenPoints(e1.origin, e2.origin, "progs/bolt3.mdl", '0 0 0', 0.2);
if (trace_fraction < 1) {
if (world.model == "maps/x1end.bsp") {
T_RadiusDamage(e2, self, dam, world);
}
else if (trace_ent.classname == "player")
T_Damage(trace_ent, self, self, dam);
return FALSE;
}
return TRUE;
/*
local entity bolt;
bolt = spawn();
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING1);
WriteEntity (MSG_BROADCAST, bolt);
WriteCoord (MSG_BROADCAST, e1.origin_x);
WriteCoord (MSG_BROADCAST, e1.origin_y);
WriteCoord (MSG_BROADCAST, e1.origin_z);
WriteCoord (MSG_BROADCAST, e2.origin_x);
WriteCoord (MSG_BROADCAST, e2.origin_y);
WriteCoord (MSG_BROADCAST, e2.origin_z);
bolt.think = SUB_Remove;
bolt.nextthink = time + 0.2;
*/
};
// randomly create a fork
void(entity e) forkbolt =
{
local entity bolt;
local vector vec,org;
if (random() * 10 < 4) return;
bolt = spawn(); // spawn the bolt
vec = normalize(e.owner.origin - e.origin);
bolt.angles = vectoangles(vec);
makevectors(bolt.angles);
// do some complicated stuff to make sure the fork goes roughly the right
// direction, and doesnt look 'fake' (random in a controlled way?)
org = e.origin + v_forward*(random()*self.distance);
org = org + v_right*(random()*(self.distance*2)-self.distance);
org = org + v_up*(random()*(self.distance*2)-self.distance);
traceline(e.origin, org, TRUE, self);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); // make some lightning
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, bolt);
WriteCoord (MSG_BROADCAST, e.origin_x);
WriteCoord (MSG_BROADCAST, e.origin_y);
WriteCoord (MSG_BROADCAST, e.origin_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);
bolt.think = SUB_Remove;
bolt.nextthink = time + 0.5;
};
// O.k. enough freakin' lightning, already.
void() lightning_finish =
{
if (self.style >= 12)
lightstyle(self.style, "a");
self.think = lightning_trigger;
if (self.targetname == "")
self.nextthink = time + self.waitmin + random() * (self.waitmax - self.waitmin);
};
float(entity parent, float lcount) randomRecursive =
{
local float dist, rnd, longbolt, newcount, dosecond;
local vector dir;
local entity newchild;
if (lcount > 4)
return lcount;
else
newcount = lcount + 1;
dosecond = TRUE;
if (newcount == 1) // don't fork on first bolt
dosecond = FALSE;
// create a left hand branch
rnd = random();
dist = 128 * floor(1 + rnd * 4);
dir = '0 0 -1';
dir_x = (random() * 1) - 0.5;
dir_y = (random() * 1) - 0.5;
dir = normalize(dir);
traceline(parent.origin, parent.origin + (dir * dist), FALSE, world);
// create the new endpoint entity
newchild = spawn();
newchild.classname = "lightning_bolt";
newchild.owner = parent;
newchild.origin = trace_endpos;
newchild.think = SUB_Remove;
newchild.nextthink = time + 0.1;
// draw the lightning bolt
DoABolt(parent, newchild, self.dmg);
if (trace_fraction == 1) { // no intersection, do another bolt from the new child
newcount = randomRecursive(newchild, newcount);
}
if (!dosecond)
return newcount;
longbolt = FALSE;
if (random() < 0.3)
longbolt = TRUE;
// do right hand branch
rnd = random();
dist = 128 * floor(1 + (3 * longbolt) + rnd * 4);
dir = '0 0 -1';
dir_x = (random() * 1) - 0.5;
dir_y = (random() * 1) - 0.5;
dir = normalize(dir);
traceline(parent.origin, parent.origin + (dir * dist), FALSE, world);
// create the new endpoint entity
newchild = spawn();
newchild.classname = "lightning_bolt";
newchild.owner = parent;
newchild.origin = trace_endpos;
newchild.think = SUB_Remove;
newchild.nextthink = time + 0.1;
// draw the lightning bolt
DoABolt(parent, newchild, self.dmg);
if ((trace_fraction == 1) && (longbolt)) { // no intersection, do another bolt from the new child
newcount = randomRecursive(newchild, newcount);
}
return newcount;
};
// Lets see some action, dammit!
void() lightning_trigger =
{
local entity lpos;
local float done;
// Sound should go here!
if (self.x_flags == 1)
sound (self, CHAN_AUTO, "ambience/elect.wav", 1, ATTN_NORM);
else
sound (self, CHAN_AUTO, "ambience/thunder1.wav", 0.7, ATTN_NORM);
//return;
if (!self.target) {
// randomize the lightning bolts
randomRecursive(self, 0);
}
else {
done = FALSE;
traceline(self.origin, self.owner.origin, FALSE, world);
DoABolt(self,self.owner, self.dmg);
// inefficient, but since find() can only match string fields... <sigh>
lpos = find(world, classname, "lightning_waypoint");
while ((lpos != world) && !(done))
{
if (lpos.style == self.style)
if (lpos.owner != world)
{
if (self.spawnflags & 1) forkbolt(lpos);
traceline(lpos.origin, lpos.owner.origin, FALSE, world);
if (!DoABolt(lpos, lpos.owner, self.dmg))
done = TRUE;
}
lpos = find(lpos, classname, "lightning_waypoint");
}
}
if (self.style >= 12)
lightstyle(self.style, "z");
self.think = lightning_finish;
self.nextthink = time + 0.3;
};
// Lightning endpoint spawn
void() lightning_ep_start =
{
local entity shnook;
if (self.target)
{
shnook = world;
do
{
shnook = find(shnook, targetname, self.target);
} while (shnook.classname != "lightning_waypoint");
self.owner = shnook;
}
else self.owner = world;
};
void() lightning_waypoint =
{
self.think = lightning_ep_start;
self.nextthink = time + 0.2;
};
// Lightning startpoint spawn
void() lightning_sp_start =
{
local entity shnook;
if (self.target) {
shnook = world;
do
{
shnook = find(shnook, targetname, self.target);
} while (shnook.classname != "lightning_waypoint");
// Safety measure in case map designer assigns lights target too...
}
self.owner = shnook;
self.think = self.use = lightning_trigger;
if (self.targetname == "")
self.nextthink = time + self.waitmin + random() * (self.waitmax - self.waitmin);
};
void() info_lightning =
{
if (deathmatch) {
remove(self);
return;
}
//if (!self.style)
// objerror("info_lightning has no style");
if (self.style && (self.style < 12))
objerror("info_lightning has invalid style");
// Ridah: target no longer required, but used if present
//if (!self.target)
// objerror("info_lightning has no target");
if (!self.waitmin) self.waitmin = 3;
if (!self.waitmax) self.waitmax = 10;
if (!self.distance) self.distance = 64;
if (!self.dmg) self.dmg = 50;
if (self.style >= 12)
lightstyle(self.style, "a");
if (self.x_flags == 1)
precache_sound ("ambience/elect.wav");
else
precache_sound ("ambience/thunder1.wav");
self.think = lightning_sp_start; // wait for all our buddies to spawn
self.nextthink = time + 0.2;
};
// End Xmen