How to make a weapon shoot through walls?
Moderator: InsideQC Admins
13 posts
• Page 1 of 1
How to make a weapon shoot through walls?
Hi, I put a half-life style gauss gun to Quake, and I want to make it shoot through walls... How is this possible?
It's a hitscan weapon though.
Any help will be appreciated.
EDIT: I created a method where an entity is created at trace_endpos + v_forward*2 (inside the wall) and checks every frame if pointcontents is not CONTENT_EMPTY, but it's still... wrong. When I fire it at a very thick wall it takes about 3 seconds to "shoot" the beam at the other end of the wall.
Also, if I do a while loop I get a runaway loop error.
Screenshots and code below.
Shooting at wall:
The shoot-thru:
Here's the code.
It's a hitscan weapon though.
Any help will be appreciated.
EDIT: I created a method where an entity is created at trace_endpos + v_forward*2 (inside the wall) and checks every frame if pointcontents is not CONTENT_EMPTY, but it's still... wrong. When I fire it at a very thick wall it takes about 3 seconds to "shoot" the beam at the other end of the wall.
Also, if I do a while loop I get a runaway loop error.
Screenshots and code below.
Shooting at wall:
The shoot-thru:
Here's the code.
- Code: Select all
void() ShootThrough =
{
self.nextthink = time;
makevectors (self.angles);
if (pointcontents(self.origin) != CONTENT_EMPTY)
self.origin = self.origin + v_forward*2;
if (pointcontents(self.origin) == CONTENT_EMPTY)
{
dprint ("gauss succesfully fired through that wall!\n");
traceline (self.origin, self.origin + v_forward*600, FALSE, self);
ParseBeam ();
if (trace_fraction == 1)
return;
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, self.health*4);
trace_ent.deathtype = "gauss";
T_Damage (trace_ent, self, self.owner, self.health);
}
remove(self);
}
};
void() W_FireGauss =
{
local vector org;
local float damage;
local entity e;
sound (self, CHAN_WEAPON, "weapons/gauss2.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
if (self.currentammo == 1)
{
self.currentammo = self.ammo_cells = self.ammo_cells - 1; // that's just not to go to -1, but will do less damage
damage = 10;
}
else
{
self.currentammo = self.ammo_cells = self.ammo_cells - 2;
damage = 20;
}
makevectors (self.v_angle);
org = self.origin + v_right*8 + '0 0 16';
ParseBeam ();
traceline (org, org + v_forward*1000, FALSE, self);
if (trace_fraction == 1)
return;
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage*4);
trace_ent.deathtype = "gauss";
T_Damage (trace_ent, self, self, damage);
}
e = spawn ();
e.owner = self;
e.health = damage;
e.origin = trace_endpos + v_forward*2;
e.angles = vectoangles(v_forward);
e.nextthink = time;
e.think = ShootThrough;
};
-

Orion - Posts: 476
- Joined: Fri Jan 12, 2007 6:32 pm
- Location: Brazil
There was once a mod -- and I do not remember what it was -- that had a black hole gun. Basically you shot it at a wall and it would search through until it found the wall on the other side (if there was an opposite side). Upon success, it would open a portal on both ends, and any player that stepped into the portal on one side would teleport to the other side. It was a very clever weapon.
I examined the code and this is what I remember about how it worked:
1. Traceline from your gun to the wall. If you hit a target, do damage to it (actually I think the portal didn't do damage but whatever), step forward 8 units, set the trace_ignore to that entity, and traceline again. Repeat until you find a wall.
2. Step forward fifty or a hundred or so units and perform a pointcontents check. Repeat this step until you find non-solid area OR you hit your loop limit (say, 10-15 attempts).
3. If your loop never found open air, quit. Otherwise, traceline backwards (ignoring entities) to find the other side of the wall, and move forwards 1-4 or so units to get slightly away from the wall.
4. Because we're making a portal, we need to make sure there's enough space in the open area for a player to teleport to it. Perform a bunch of tracelines in several directions to figure out how to place the portal sufficiently far away from the floor and other walls so that a player can fit inside. If you determine that there isn't enough space or that something else is wrong, quit.
5. If successful, spawn a visual portal on both sides of the wall and give them a touch function for teleporting players.
Obviously, steps 4 and 5 do not apply to a gun that only needs to shoot through one or many walls. You would want to replace these steps with this:
4. Spawn an entity that will think next frame. Set its owner to the player and give it the damage amount, direction fired, and a count of how many walls it's plowed through (it will increase this count and give it to any entities it spawns).
5. Upon its think, begin again at step 1 with the traceline to hit a wall. Damage entities as normal until it hits a wall. When it does hit a wall, only try to bore through it if your "bullet" hasn't hit its wall limit (say, 5 walls).
I should note that step 1 is a potential problem in a rare, freak case when the player fires through 50 entities. I used to make maps where the player fought hundreds of dogs all lined up in neat little rows. The chain lightning gun and railgun were AWESOME on that map.
If you want to account for such a case and avoid the dreaded infinite loop trigger, you can have each segment of step 1 and 2 separated by a frame by spawning an entity like in our revised steps 4 and 5. Thus, every time it hits a monster it spawns a new entity and waits to go through it. (note: this code is simpler than the loop, and safer, and after reading your code I've concluded that this is exactly what you're doing).
This may be unnecessary though. If you limit your wall digging code to 15 tries at 50 units each, you can go through a wall up to 750 units in length. 15 loop iterations ain't so bad if your loop isn't doing a ton of work. Likewise, there usually won't be more than, say, 15 enemies in a row (though that loop is doing a lot more work for damaging and killing the enemies, so this is a potential weak point). Split it up as you see necessary.
BTW, I just read your code. Your code is already very close to what I'm talking about and could be modified in the following ways:
If you hit a damagable entity, go through it the same way you're doing.
If you hit a wall, step forward by 50 instead of 2. Continue to do this until you hit empty air or you run out of tries (see below).
If this gets you into empty air, traceline (ignoring ents) backwards to find the wall again so you don't jump too far. Now you can traceline forward again 600 or 2000 units, hitting ents as normal. Do damage to entities and set up for the next adventure (nextthink).
Add a counter to test how many times it's ended up in a solid without finding an air gap (or far it's traveled). Once it goes too long, remove the entity so it doesn't fly forever after leaving the level. You might also add a limit for how many walls it will go through total.
Remember to set the entity you last hit as the ignore/owner entity for the traceline (I think if you start the traceline inside the entity but don't say to ignore it, the traceline will ignore it and all other entities instead of hitting the entities past it).
There, that's simpler than my earlier explanation, is immune to infinite loops triggering, and you don't even need to change your code much.
I hope that helps!
I examined the code and this is what I remember about how it worked:
1. Traceline from your gun to the wall. If you hit a target, do damage to it (actually I think the portal didn't do damage but whatever), step forward 8 units, set the trace_ignore to that entity, and traceline again. Repeat until you find a wall.
2. Step forward fifty or a hundred or so units and perform a pointcontents check. Repeat this step until you find non-solid area OR you hit your loop limit (say, 10-15 attempts).
3. If your loop never found open air, quit. Otherwise, traceline backwards (ignoring entities) to find the other side of the wall, and move forwards 1-4 or so units to get slightly away from the wall.
4. Because we're making a portal, we need to make sure there's enough space in the open area for a player to teleport to it. Perform a bunch of tracelines in several directions to figure out how to place the portal sufficiently far away from the floor and other walls so that a player can fit inside. If you determine that there isn't enough space or that something else is wrong, quit.
5. If successful, spawn a visual portal on both sides of the wall and give them a touch function for teleporting players.
Obviously, steps 4 and 5 do not apply to a gun that only needs to shoot through one or many walls. You would want to replace these steps with this:
4. Spawn an entity that will think next frame. Set its owner to the player and give it the damage amount, direction fired, and a count of how many walls it's plowed through (it will increase this count and give it to any entities it spawns).
5. Upon its think, begin again at step 1 with the traceline to hit a wall. Damage entities as normal until it hits a wall. When it does hit a wall, only try to bore through it if your "bullet" hasn't hit its wall limit (say, 5 walls).
I should note that step 1 is a potential problem in a rare, freak case when the player fires through 50 entities. I used to make maps where the player fought hundreds of dogs all lined up in neat little rows. The chain lightning gun and railgun were AWESOME on that map.
If you want to account for such a case and avoid the dreaded infinite loop trigger, you can have each segment of step 1 and 2 separated by a frame by spawning an entity like in our revised steps 4 and 5. Thus, every time it hits a monster it spawns a new entity and waits to go through it. (note: this code is simpler than the loop, and safer, and after reading your code I've concluded that this is exactly what you're doing).
This may be unnecessary though. If you limit your wall digging code to 15 tries at 50 units each, you can go through a wall up to 750 units in length. 15 loop iterations ain't so bad if your loop isn't doing a ton of work. Likewise, there usually won't be more than, say, 15 enemies in a row (though that loop is doing a lot more work for damaging and killing the enemies, so this is a potential weak point). Split it up as you see necessary.
BTW, I just read your code. Your code is already very close to what I'm talking about and could be modified in the following ways:
If you hit a damagable entity, go through it the same way you're doing.
If you hit a wall, step forward by 50 instead of 2. Continue to do this until you hit empty air or you run out of tries (see below).
If this gets you into empty air, traceline (ignoring ents) backwards to find the wall again so you don't jump too far. Now you can traceline forward again 600 or 2000 units, hitting ents as normal. Do damage to entities and set up for the next adventure (nextthink).
Add a counter to test how many times it's ended up in a solid without finding an air gap (or far it's traveled). Once it goes too long, remove the entity so it doesn't fly forever after leaving the level. You might also add a limit for how many walls it will go through total.
Remember to set the entity you last hit as the ignore/owner entity for the traceline (I think if you start the traceline inside the entity but don't say to ignore it, the traceline will ignore it and all other entities instead of hitting the entities past it).
There, that's simpler than my earlier explanation, is immune to infinite loops triggering, and you don't even need to change your code much.
I hope that helps!
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
- Wazat
- Posts: 771
- Joined: Fri Oct 15, 2004 9:50 pm
- Location: Middle 'o the desert, USA
Nice!
Thank you Wazat!
But my code was heavily modified... I had a little trouble at the beginning.
Also, the gauss gun will only go through one wall.
It's all at the fire function:
Thank you Wazat!
But my code was heavily modified... I had a little trouble at the beginning.
Also, the gauss gun will only go through one wall.
It's all at the fire function:
- Code: Select all
void() W_FireGauss =
{
local vector org, tendpos;
local float damage, fwd, tries;
local entity tent, e;
sound (self, CHAN_WEAPON, "weapons/gauss2.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
if (self.currentammo == 1)
{
self.currentammo = self.ammo_cells = self.ammo_cells - 1; // that's just not to go to -1, but will do less damage
damage = 10;
}
else
{
self.currentammo = self.ammo_cells = self.ammo_cells - 2;
damage = 20;
}
makevectors (self.v_angle);
org = self.origin + v_right*8 + '0 0 16';
ParseBeam (org);
traceline (org, org + v_forward*1000, FALSE, self);
if (trace_fraction == 1)
return;
tendpos = trace_endpos;
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage*4);
trace_ent.deathtype = "gauss";
T_Damage (trace_ent, self, self, damage);
org = tendpos + v_forward*8;
tent = trace_ent;
ParseBeam (org);
traceline (org, org + v_forward*600, FALSE, tent);
if (trace_fraction == 1)
return;
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage*4);
trace_ent.deathtype = "gauss";
T_Damage (trace_ent, self, self, damage);
}
return;
}
fwd = 0;
while (tries < 15)
{
fwd = fwd + 50;
tries = tries + 1;
if (pointcontents(tendpos + v_forward*fwd) == CONTENT_EMPTY)
tries = 15;
}
if (pointcontents(tendpos + v_forward*fwd) == CONTENT_EMPTY)
{
dprint ("shoot-through successfull!\n");
e = spawn ();
e.origin = tendpos + v_forward*fwd;
traceline (e.origin, e.origin - v_forward*300, TRUE, e);
e.origin = trace_endpos + v_forward*4;
ParseBeam (e.origin);
traceline (e.origin, e.origin + v_forward*600, FALSE, e);
if (trace_fraction == 1)
{
remove(e);
return;
}
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage*4);
trace_ent.deathtype = "gauss";
T_Damage (trace_ent, self, self, damage);
}
remove(e);
}
};
-

Orion - Posts: 476
- Joined: Fri Jan 12, 2007 6:32 pm
- Location: Brazil
Sounds like some thing similar to this portal mod or this one or even this newer one that seems as a rip off of previous ones..
Wazat wrote:There was once a mod -- and I do not remember what it was -- that had a black hole gun. Basically you shot it at a wall and it would search through until it found the wall on the other side (if there was an opposite side). Upon success, it would open a portal on both ends, and any player that stepped into the portal on one side would teleport to the other side. It was a very clever weapon.
-

xaGe - Posts: 461
- Joined: Wed Mar 01, 2006 8:29 am
- Location: Upstate, New York
if your trace hits a wall, try a new trace just on the other side of that wall.
if the trace starts solid, the trace fraction is often 1. if the trace fraction is 1, then it didn't hit anything, and the trace will continue through to hit monsters.
I'm not sure if it'll still hit the world surfaces when it started solid or not.
if the trace starts solid, the trace fraction is often 1. if the trace fraction is 1, then it didn't hit anything, and the trace will continue through to hit monsters.
I'm not sure if it'll still hit the world surfaces when it started solid or not.
- Spike
- Posts: 2892
- Joined: Fri Nov 05, 2004 3:12 am
- Location: UK
The gauss gun is now working perfectly.
I also made a hole gun which makes you teleport through walls.
I uploaded a video doing a speedrun using the gun on e2m5.
I wasted a little time because of misplaced holes.
http://www.youtube.com/watch?v=EsEbYybWAgk
I also made a hole gun which makes you teleport through walls.
I uploaded a video doing a speedrun using the gun on e2m5.
I wasted a little time because of misplaced holes.
http://www.youtube.com/watch?v=EsEbYybWAgk
-

Orion - Posts: 476
- Joined: Fri Jan 12, 2007 6:32 pm
- Location: Brazil
r00k wrote:I havent read thru your code atm in a hurry, but look at id software's original lg code in weapons.qc, as there was a bug that allowed the lg damage to transpose thru the wall.
MeTcHsteekle wrote:they do it in QDQ in shub's pit
That's actually a different bug. The lightning beam that kills the monsters actually starts on the other side of the wall...
-

Lardarse - Posts: 266
- Joined: Sat Nov 05, 2005 1:58 pm
- Location: Bristol, UK
13 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest
