Forum

How to make a weapon shoot through walls?

Discuss programming in the QuakeC language.

Moderator: InsideQC Admins

How to make a weapon shoot through walls?

Postby Orion » Fri Feb 20, 2009 10:15 pm

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:
Image

The shoot-thru:
Image


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;
};
User avatar
Orion
 
Posts: 476
Joined: Fri Jan 12, 2007 6:32 pm
Location: Brazil

Postby r00k » Sat Feb 21, 2009 7:03 pm

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. :P
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Orion » Sat Feb 21, 2009 11:34 pm

I'm sorry but the lightning gun can't do any damad ge through a wall...
I'm a bit druynk here.. sorry for mispelled worsds..
Afaiik the lg don't do amage through a wall.. unless if you can prove the contrary.
User avatar
Orion
 
Posts: 476
Joined: Fri Jan 12, 2007 6:32 pm
Location: Brazil

Postby MeTcHsteekle » Sat Feb 21, 2009 11:41 pm

they do it in QDQ in shub's pit

edit: http://www.youtube.com/watch?v=h81irjuSweM around 3:40
bah
MeTcHsteekle
 
Posts: 399
Joined: Thu May 15, 2008 10:46 pm
Location: its a secret

Postby r00k » Sun Feb 22, 2009 5:17 am

Ya its a bug but might help you figure out a method. :)
unless its a collision bug with doors instead of just a normal wall.

I'll try to tweak something out in the morning ;)
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Wazat » Sun Feb 22, 2009 6:16 pm

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. :D

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. :D

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

Postby Orion » Sun Feb 22, 2009 8:52 pm

Nice! :)
Thank you Wazat! :D

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);
   }
};
User avatar
Orion
 
Posts: 476
Joined: Fri Jan 12, 2007 6:32 pm
Location: Brazil

Postby xaGe » Mon Feb 23, 2009 1:56 am

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.
User avatar
xaGe
 
Posts: 461
Joined: Wed Mar 01, 2006 8:29 am
Location: Upstate, New York

Postby Spike » Mon Feb 23, 2009 12:00 pm

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.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby Orion » Mon Feb 23, 2009 10:38 pm

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
User avatar
Orion
 
Posts: 476
Joined: Fri Jan 12, 2007 6:32 pm
Location: Brazil

Postby Wazat » Tue Feb 24, 2009 1:36 am

LOL, awesome vid. I'm glad you got it working!
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

Postby Lardarse » Wed Mar 11, 2009 12:11 am

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. :P

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...
User avatar
Lardarse
 
Posts: 266
Joined: Sat Nov 05, 2005 1:58 pm
Location: Bristol, UK

Postby Urre » Wed Mar 11, 2009 7:11 am

Hahah, cool clip
I was once a Quake modder
User avatar
Urre
 
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon


Return to QuakeC Programming

Who is online

Users browsing this forum: No registered users and 1 guest