From f3e095ab00b34971c1b4ea6ef600dae83baaf7ee Mon Sep 17 00:00:00 2001 From: cholleme <> Date: Sat, 23 Nov 2002 19:43:13 +0000 Subject: [PATCH] Added particle emitters --- subs.qc | 659 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 343 insertions(+), 316 deletions(-) diff --git a/subs.qc b/subs.qc index daf57bc..a25b837 100644 --- a/subs.qc +++ b/subs.qc @@ -1,316 +1,343 @@ - - -void() SUB_Null = {}; - -void() SUB_Remove = {remove(self);}; - - -/* -QuakeEd only writes a single float for angles (bad idea), so up and down are -just constant angles. -*/ -vector() SetMovedir = -{ - if (self.angles == '0 -1 0') - self.movedir = '0 0 1'; - else if (self.angles == '0 -2 0') - self.movedir = '0 0 -1'; - else - { - makevectors (self.angles); - self.movedir = v_forward; - } - - self.angles = '0 0 0'; -}; - -/* -================ -InitTrigger -================ -*/ -void() InitTrigger = -{ -// trigger angles are used for one-way touches. An angle of 0 is assumed -// to mean no restrictions, so use a yaw of 360 instead. - if (self.angles != '0 0 0') - SetMovedir (); - self.solid = SOLID_TRIGGER; - setmodel (self, self.model); // set size and link into world - self.movetype = MOVETYPE_NONE; - self.modelindex = 0; - self.model = ""; -}; - -/* -============= -SUB_CalcMove - -calculate self.velocity and self.nextthink to reach dest from -self.origin traveling at speed -=============== -*/ -void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt = -{ -local entity stemp; - stemp = self; - self = ent; - - SUB_CalcMove (tdest, tspeed, func); - self = stemp; -}; - -void(vector tdest, float tspeed, void() func) SUB_CalcMove = -{ -local vector vdestdelta; -local float len, traveltime; - - if (!tspeed) - objerror("No speed is defined!"); - - self.think1 = func; - self.finaldest = tdest; - self.think = SUB_CalcMoveDone; - - if (tdest == self.origin) - { - self.velocity = '0 0 0'; - self.nextthink = self.ltime + 0.1; - return; - } - -// set destdelta to the vector needed to move - vdestdelta = tdest - self.origin; - -// calculate length of vector - len = vlen (vdestdelta); - -// divide by speed to get time to reach dest - traveltime = len / tspeed; - - if (traveltime < 0.1) - { - self.velocity = '0 0 0'; - self.nextthink = self.ltime + 0.1; - return; - } - -// set nextthink to trigger a think when dest is reached - self.nextthink = self.ltime + traveltime; - -// scale the destdelta vector by the time spent traveling to get velocity - self.velocity = vdestdelta * (1/traveltime); // qcc won't take vec/float -}; - -/* -============ -After moving, set origin to exact final destination -============ -*/ -void() SUB_CalcMoveDone = -{ - setorigin(self, self.finaldest); - self.velocity = '0 0 0'; - self.nextthink = -1; - if (self.think1) - self.think1(); -}; - - -/* -============= -SUB_CalcAngleMove - -calculate self.avelocity and self.nextthink to reach destangle from -self.angles rotating - -The calling function should make sure self.think is valid -=============== -*/ -void(entity ent, vector destangle, float tspeed, void() func) SUB_CalcAngleMoveEnt = -{ -local entity stemp; - stemp = self; - self = ent; - SUB_CalcAngleMove (destangle, tspeed, func); - self = stemp; -}; - -void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove = -{ -local vector destdelta; -local float len, traveltime; - - if (!tspeed) - objerror("No speed is defined!"); - -// set destdelta to the vector needed to move - destdelta = destangle - self.angles; - -// calculate length of vector - len = vlen (destdelta); - -// divide by speed to get time to reach dest - traveltime = len / tspeed; - -// set nextthink to trigger a think when dest is reached - self.nextthink = self.ltime + traveltime; - -// scale the destdelta vector by the time spent traveling to get velocity - self.avelocity = destdelta * (1 / traveltime); - - self.think1 = func; - self.finalangle = destangle; - self.think = SUB_CalcAngleMoveDone; -}; - -/* -============ -After rotating, set angle to exact final angle -============ -*/ -void() SUB_CalcAngleMoveDone = -{ - self.angles = self.finalangle; - self.avelocity = '0 0 0'; - self.nextthink = -1; - if (self.think1) - self.think1(); -}; - - -//============================================================================= - -void() DelayThink = -{ - activator = self.enemy; - SUB_UseTargets (); - remove(self); -}; - -/* -============================== -SUB_UseTargets - -the global "activator" should be set to the entity that initiated the firing. - -If self.delay is set, a DelayedUse entity will be created that will actually -do the SUB_UseTargets after that many seconds have passed. - -Centerprints any self.message to the activator. - -Removes all entities with a targetname that match self.killtarget, -and removes them, so some events can remove other triggers. - -Search for (string)targetname in all entities that -match (string)self.target and call their .use function - -============================== -*/ -void() SUB_UseTargets = -{ - local entity t, stemp, otemp, act; - -// -// check for a delay -// - if (self.delay) - { - // create a temp object to fire at a later time - t = spawn(); - t.classname = "DelayedUse"; - t.nextthink = time + self.delay; - t.think = DelayThink; - t.enemy = activator; - t.message = self.message; - t.killtarget = self.killtarget; - t.target = self.target; - return; - } - - -// -// print the message -// - if (activator.classname == "player" && self.message != "") - { - centerprint (activator, self.message); - if (!self.noise) - sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); - } - -// -// kill the killtagets -// - if (self.killtarget) - { - t = world; - do - { - t = find (t, targetname, self.killtarget); - if (!t) - return; - remove (t); - } while ( 1 ); - } - -// -// fire targets -// - if (self.target) - { - act = activator; - t = world; - do - { - t = find (t, targetname, self.target); - if (!t) - { - return; - } - stemp = self; - otemp = other; - self = t; - other = stemp; - if (self.use != SUB_Null) - { - if (self.use) - self.use (); - } - self = stemp; - other = otemp; - activator = act; - } while ( 1 ); - } - - -}; - - -/* - -in nightmare mode, all attack_finished times become 0 -some monsters refire twice automatically - -*/ - -void(float normal) SUB_AttackFinished = -{ - self.cnt = 0; // refire count for nightmare - if (skill != 3) - self.attack_finished = time + normal; -}; - -float (entity targ) visible; - -void (void() thinkst) SUB_CheckRefire = -{ - if (skill != 3) - return; - if (self.cnt == 1) - return; - if (!visible (self.enemy)) - return; - self.cnt = 1; - self.think = thinkst; -}; + + +void() SUB_Null = {}; + +void() SUB_Remove = {remove(self);}; + + +/* +QuakeEd only writes a single float for angles (bad idea), so up and down are +just constant angles. +*/ +vector() SetMovedir = +{ + if (self.angles == '0 -1 0') + self.movedir = '0 0 1'; + else if (self.angles == '0 -2 0') + self.movedir = '0 0 -1'; + else + { + makevectors (self.angles); + self.movedir = v_forward; + } + + self.angles = '0 0 0'; +}; + +/* +================ +InitTrigger +================ +*/ +void() InitTrigger = +{ +// trigger angles are used for one-way touches. An angle of 0 is assumed +// to mean no restrictions, so use a yaw of 360 instead. + if (self.angles != '0 0 0') + SetMovedir (); + self.solid = SOLID_TRIGGER; + setmodel (self, self.model); // set size and link into world + self.movetype = MOVETYPE_NONE; + self.modelindex = 0; + self.model = ""; +}; + +/* +============= +SUB_CalcMove + +calculate self.velocity and self.nextthink to reach dest from +self.origin traveling at speed +=============== +*/ +void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt = +{ +local entity stemp; + stemp = self; + self = ent; + + SUB_CalcMove (tdest, tspeed, func); + self = stemp; +}; + +void(vector tdest, float tspeed, void() func) SUB_CalcMove = +{ +local vector vdestdelta; +local float len, traveltime; + + if (!tspeed) + objerror("No speed is defined!"); + + self.think1 = func; + self.finaldest = tdest; + self.think = SUB_CalcMoveDone; + + if (tdest == self.origin) + { + self.velocity = '0 0 0'; + self.nextthink = self.ltime + 0.1; + return; + } + +// set destdelta to the vector needed to move + vdestdelta = tdest - self.origin; + +// calculate length of vector + len = vlen (vdestdelta); + +// divide by speed to get time to reach dest + traveltime = len / tspeed; + + if (traveltime < 0.1) + { + self.velocity = '0 0 0'; + self.nextthink = self.ltime + 0.1; + return; + } + +// set nextthink to trigger a think when dest is reached + self.nextthink = self.ltime + traveltime; + +// scale the destdelta vector by the time spent traveling to get velocity + self.velocity = vdestdelta * (1/traveltime); // qcc won't take vec/float +}; + +/* +============ +After moving, set origin to exact final destination +============ +*/ +void() SUB_CalcMoveDone = +{ + setorigin(self, self.finaldest); + self.velocity = '0 0 0'; + self.nextthink = -1; + if (self.think1) + self.think1(); +}; + + +/* +============= +SUB_CalcAngleMove + +calculate self.avelocity and self.nextthink to reach destangle from +self.angles rotating + +The calling function should make sure self.think is valid +=============== +*/ +void(entity ent, vector destangle, float tspeed, void() func) SUB_CalcAngleMoveEnt = +{ +local entity stemp; + stemp = self; + self = ent; + SUB_CalcAngleMove (destangle, tspeed, func); + self = stemp; +}; + +void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove = +{ +local vector destdelta; +local float len, traveltime; + + if (!tspeed) + objerror("No speed is defined!"); + +// set destdelta to the vector needed to move + destdelta = destangle - self.angles; + +// calculate length of vector + len = vlen (destdelta); + +// divide by speed to get time to reach dest + traveltime = len / tspeed; + +// set nextthink to trigger a think when dest is reached + self.nextthink = self.ltime + traveltime; + +// scale the destdelta vector by the time spent traveling to get velocity + self.avelocity = destdelta * (1 / traveltime); + + self.think1 = func; + self.finalangle = destangle; + self.think = SUB_CalcAngleMoveDone; +}; + +/* +============ +After rotating, set angle to exact final angle +============ +*/ +void() SUB_CalcAngleMoveDone = +{ + self.angles = self.finalangle; + self.avelocity = '0 0 0'; + self.nextthink = -1; + if (self.think1) + self.think1(); +}; + + +//============================================================================= + +void() DelayThink = +{ + activator = self.enemy; + SUB_UseTargets (); + remove(self); +}; + +/* +============================== +SUB_UseTargets + +the global "activator" should be set to the entity that initiated the firing. + +If self.delay is set, a DelayedUse entity will be created that will actually +do the SUB_UseTargets after that many seconds have passed. + +Centerprints any self.message to the activator. + +Removes all entities with a targetname that match self.killtarget, +and removes them, so some events can remove other triggers. + +Search for (string)targetname in all entities that +match (string)self.target and call their .use function + +============================== +*/ +void() SUB_UseTargets = +{ + local entity t, stemp, otemp, act; + +// +// check for a delay +// + if (self.delay) + { + // create a temp object to fire at a later time + t = spawn(); + t.classname = "DelayedUse"; + t.nextthink = time + self.delay; + t.think = DelayThink; + t.enemy = activator; + t.message = self.message; + t.killtarget = self.killtarget; + t.target = self.target; + return; + } + + +// +// print the message +// + if (activator.classname == "player" && self.message != "") + { + centerprint (activator, self.message); + if (!self.noise) + sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); + } + +// +// kill the killtagets +// + if (self.killtarget) + { + t = world; + do + { + t = find (t, targetname, self.killtarget); + if (!t) + return; + remove (t); + } while ( 1 ); + } + +// +// fire targets +// + if (self.target) + { + act = activator; + t = world; + do + { + t = find (t, targetname, self.target); + if (!t) + { + return; + } + stemp = self; + otemp = other; + self = t; + other = stemp; + if (self.use != SUB_Null) + { + if (self.use) + self.use (); + } + self = stemp; + other = otemp; + activator = act; + } while ( 1 ); + } + + +}; + + +/* + +in nightmare mode, all attack_finished times become 0 +some monsters refire twice automatically + +*/ + +void(float normal) SUB_AttackFinished = +{ + self.cnt = 0; // refire count for nightmare + if (skill != 3) + self.attack_finished = time + normal; +}; + +float (entity targ) visible; + +void (void() thinkst) SUB_CheckRefire = +{ + if (skill != 3) + return; + if (self.cnt == 1) + return; + if (!visible (self.enemy)) + return; + self.cnt = 1; + self.think = thinkst; +}; + +//PENTA: new particle support +void (entity ent, float pcount, string effectname) SUB_BasicEmitter = +{ + WriteByte (MSG_BROADCAST, SVC_BASICEMITTER); + WriteCoord (MSG_BROADCAST, ent.origin_x); + WriteCoord (MSG_BROADCAST, ent.origin_y); + WriteCoord (MSG_BROADCAST, ent.origin_z); + WriteByte (MSG_BROADCAST, pcount); + WriteString(MSG_BROADCAST, effectname); +}; + +//PENTA: new particle support +void (entity ent, float pcount, float tick, float life, string effectname) SUB_ExtendedEmitter = +{ + WriteByte (MSG_BROADCAST, SVC_EXTENDEDEMITTER); + WriteCoord (MSG_BROADCAST, ent.origin_x); + WriteCoord (MSG_BROADCAST, ent.origin_y); + WriteCoord (MSG_BROADCAST, ent.origin_z); + WriteCoord (MSG_BROADCAST, ent.velocity_x); + WriteCoord (MSG_BROADCAST, ent.velocity_y); + WriteCoord (MSG_BROADCAST, ent.velocity_z); + WriteByte (MSG_BROADCAST, pcount); + WriteLong (MSG_BROADCAST, life*100); + WriteLong (MSG_BROADCAST, tick*100); + WriteString(MSG_BROADCAST, effectname); +}; \ No newline at end of file