// CQ void VampForce(); void HookStatusCheck(); // CQ /* Laser Grapple. (Quake2 Style Hook) Addon by Tux */ /* To make comments or suggestions: tux@admdev.com */ /* DIRECTIONS */ /* First, prepare your mod directory. Create the following directory structure. quake/moddir/sound/hook/grfire.wav quake/moddir/sound/hook/grhit.wav quake/moddir/sound/hook/grreset.wav quake/moddir/progs/null.spr quake/moddir/progs/bolt.mdl Add tuthook.qc to progs.src above weapons.qc Next, go into weapons.qc and copy the following code into the precache function near the beginning of the file: precache_sound("hook/grfire.wav"); precache_sound("hook/grhit.wav"); precache_sound("hook/grreset.wav"); precache_model("progs/null.spr"); Next go to client.qc and add this line: CheckRope(); to the end of the "PlayerPreThink" function Then, add these lines to defs.qc: .entity hook; .float hooking; Next go to weapons.qc and add the following lines to the Impulse check near the end of the file. if (self.impulse == 24) FireHook (); if (self.impulse == 25) BreakHook (); The mod is now ready for compile. FOr the hook to work with a single button, make an autoexec.cfg file that contains these lines: alias +hook "impulse 24" alias -hook "impulse 25" bind +hook */ void () DrawBeam = { local vector org; org = (self.origin) + '0 0 16'; WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); WriteByte(MSG_BROADCAST, TE_LIGHTNING1); WriteEntity(MSG_BROADCAST, world); WriteCoord(MSG_BROADCAST, org_x); WriteCoord(MSG_BROADCAST, org_y); WriteCoord(MSG_BROADCAST, org_z); WriteCoord(MSG_BROADCAST, self.hook.origin_x); WriteCoord(MSG_BROADCAST, self.hook.origin_y); WriteCoord(MSG_BROADCAST, self.hook.origin_z); }; void() pull = { if (self.owner.hooking == 1) { // CQ if(other != world) { other.velocity = normalize(self.owner.origin - other.origin); other.velocity = other.velocity * 500; setorigin(self, other.origin); } else { self.owner.velocity = normalize(self.origin - self.owner.origin); self.owner.velocity = self.owner.velocity * 500; } // CQ self.think = pull; self.nextthink = time + 0.1; } else { self.owner.hooking = 0; remove(self); sound (self.owner, CHAN_WEAPON, "grapple/grreset.wav", 1, ATTN_NORM); } }; void() hookdamage = { // CQ if(infokey(self.owner, "VampHook") != "1" && infokey(self.owner, "VampHook") != "2") return; if(self.enemy.deadflag > 0) { remove(self); self.owner.hooking = 0; self.owner.HookHold = 0; // self.enemy.Hooked = 0; sound (self, CHAN_WEAPON, "grapple/grreset.wav", 1, ATTN_NORM); return; } // CQ if (self.enemy.health || self.enemy.classname != "door") { self.owner.HookHold = time + 5; self.owner.velocity = normalize(self.origin - self.owner.origin); self.owner.velocity = self.owner.velocity * 500; // start new hook mod code if(infokey(self.owner, "VampHook") != "2") { if((self.enemy.telegrenade == 2) || (self.enemy.SaberSwing == 1)) { self.owner.impulse = 25; return; } } float electrohook; if(infokey(self.owner, "VampHook") == "2") { self.enemy.deathtype = "ehook"; electrohook = self.enemy.health + 500; T_Damage(self.owner, self, self, (random()*50)); sound(self.enemy, CHAN_BODY, "grapple/ehookexplode.wav", 1, ATTN_NORM); if(self.enemy.takedamage == 0) self.enemy.takedamage = 2; } else { self.enemy.deathtype = "hook"; electrohook = 5; } T_Damage(self.enemy, self, self.owner, electrohook); if(infokey(self.owner, "VampHook") == "2") { self.owner.impulse = 25; sound(self.owner, CHAN_ITEM, "grapple/grcharge.wav", 1, ATTN_NORM); self.owner.ChargeHook = time + 3; } if( infokey(self.owner, "VampHook") == "1" ) { HookStatusCheck(); if(self.owner.health >= 500) { self.owner.health = 500; } else { self.owner.health = self.owner.health + 5; if(self.owner.health > 500) self.owner.health = 500; } VampForce(); } self.origin = self.enemy.origin; self.think = hookdamage; self.nextthink = time + 0.1; } else { self.owner.impulse = 25; // self.owner.hooking = 0; // remove(self); // sound (self.owner, CHAN_WEAPON, "grapple/grreset.wav", 1, ATTN_NORM); } }; void() PullHook = { if (other == self.owner) return; if (other == world) // Pull { // CQ self.owner.ForceJump = 0; // CQ self.solid = SOLID_NOT; self.movetype = MOVETYPE_NONE; self.think = pull; self.nextthink = time; } // CQ if (other.SaberSwing && other.health) { self.owner.ForceJump = 0; self.think = hookdamage; self.enemy = other; self.solid = SOLID_NOT; // other.Hooked = 1; self.nextthink = time; } // CQ if (other.takedamage && other.health) { // CQ self.owner.ForceJump = 0; // CQ self.think = hookdamage; self.enemy = other; self.solid = SOLID_NOT; // other.Hooked = 1; self.nextthink = time; } sound (self, CHAN_WEAPON, "grapple/grhit.wav", 1, ATTN_NORM); sound (self.owner, CHAN_WEAPON, "grapple/grhit.wav", 1, ATTN_NORM); }; void() BreakHook = { if (self.hooking == 1) { self.show_hostile = time + 0.2; remove(self.hook); self.hooking = 0; self.HookHold = 0; sound (self, CHAN_WEAPON, "grapple/grreset.wav", 1, ATTN_NORM); } }; void () FireHook = { if(self.hooking) return; if((time < self.emp) && (infokey(self, "VampHook") == "2")) { self.show_hostile = time + 0.2; if(rint(random()) < 0.5) sound(self, CHAN_AUTO, "emp/empdmg.wav", 1, ATTN_NORM); else sound(self, CHAN_AUTO, "emp/empdmg2.wav", 1, ATTN_NORM); return; } if(time < self.ChargeHook) return; if(infokey(self, "VampHook") == "2" && self.health < 51) return; self.show_hostile = time + 0.2; local entity hooky; hooky = spawn(); setorigin(hooky, self.origin + self.view_ofs); setmodel(hooky, "progsgrapple/null.spr"); setsize (hooky, '0 0 0', '0 0 0'); hooky.solid = SOLID_BBOX; hooky.movetype = MOVETYPE_FLYMISSILE; makevectors(self.v_angle); self.aiment = hooky; hooky.velocity = v_forward * 1500; hooky.owner = self; self.hook = hooky; hooky.classname = "hookend"; self.hooking = 1; hooky.touch = PullHook; //hooky.cansplash = 1; // If my splash tutorial is installed, uncomment this line if(infokey(self, "VampHook") == "2") { sound(self, CHAN_WEAPON, "grapple/efire.wav", 1, ATTN_NORM); } else { sound (self, CHAN_WEAPON, "grapple/grfire.wav", 1, ATTN_NORM); } }; void() CheckRope = { if (self.hooking == 1 && self.hook.classname == "hookend") { DrawBeam (); } };