Forum

Detecting multiple powerups...

Discuss programming in the QuakeC language.

Moderator: InsideQC Admins

Detecting multiple powerups...

Postby dayfive » Fri Dec 01, 2006 11:13 am

Ok, so say I wanted to make some code that detects if a player has acquired more than one powerup... what is a way to do this??

ive tried

Code: Select all
if ((self.items == IT_INVISIBILITY) &&
      (self.items == IT_QUAD) &&
      (self.items == IT_INVULNERABILITY))
      {
         sprint (other, "Oh noes! Powerful player running around...\n");
// more code here
      }


and

Code: Select all
if ((self.classname == "item_artifact_invisibility") &&
      (self.classname == "item_artifact_super_damage") &&
      (self.items == "item_artifact_invulnerability"))
      {
         sprint (other, "Oh noes! Powerful player running around...\n");
// more code here
      }


and neither work correctly... I'm sure this is a trivial fix, but I'm not sure what the correct way to detect the player's acquired items is..?

any help appreciated!
User avatar
dayfive
 
Posts: 77
Joined: Fri Nov 10, 2006 9:48 pm

Postby dayfive » Fri Dec 01, 2006 11:13 am

forgot to mention...

the code above appears in the powerup_touch() function in items.qc, if that helps.
User avatar
dayfive
 
Posts: 77
Joined: Fri Nov 10, 2006 9:48 pm

Postby Quake Matt » Fri Dec 01, 2006 12:59 pm

The problem is that 'other' in this context refers to the player, while 'self' refers to the powerup. Because this is the touch function of the powerup, that powerup will be self when the touch function is triggered. Likewise, the player may also have a touch function and, when that's triggered, the player will be self.

Basically, you'll want something like this (not tested!):

Code: Select all
if ((other.items & IT_INVISIBILITY) &&
      (other.items & IT_QUAD) &&
      (other.items & IT_INVULNERABILITY))
      {
         bprint ("Oh noes! Powerful player running around...\n");
// more code here
      }


This checks to see if the entity that's touching the item has the three powerups then, if it has, does a bprint (broadcasts message to all players) to let everyone know.

You might also notice that I've replaced the == in the if statement with &. This is because powerups, like most items, are stored in the player entity as bit flags. They work a bit like this:

Code: Select all
IT_Shotgun       = 1 = 0001
IT_Super_Shotgun = 2 = 0010
IT_Nailgun       = 4 = 0100
IT_Super_Nailgun = 8 = 1000

Bitwise OR:  0001 | 0100 = 0101
Bitwise AND: 1010 & 0011 = 0010


So, basically, you can use a single .items variable to store all information on lots of items, since each one only uses a single binary digit. It's probably not worth worrying about it too much yet, but if still need help with this, just ask and we'll explain what we can.

If you wanted to hide the message from the player that's just picked up the item, you'd need to use sprint again, but you'd need to call it once for each other player in the game, not just use 'other'![/code]
User avatar
Quake Matt
 
Posts: 129
Joined: Sun Jun 05, 2005 9:59 pm

Postby dayfive » Fri Dec 01, 2006 3:24 pm

Hi Quake Matt!

Thanks for your reply.

Quake Matt wrote:The problem is that 'other' in this context refers to the player, while 'self' refers to the powerup. Because this is the touch function of the powerup, that powerup will be self when the touch function is triggered. Likewise, the player may also have a touch function and, when that's triggered, the player will be self.

...

This checks to see if the entity that's touching the item has the three powerups then, if it has, does a bprint (broadcasts message to all players) to let everyone know.



so I tried your example and it didn't work out of the box, but what you said makes a lot of sense. A thought occurred that, if you touch the powerup and it checks for all 3, it won't return true unless it's the second powerup of a certain type you get, since you wont actually have all 3 at the instant you touch the third.

This is what ended up working for me based on your suggestions and advice

Code: Select all
   if (((other.items & IT_INVISIBILITY) && (other.items & IT_QUAD)) ||
   ((other.items & IT_INVISIBILITY) && (other.items & IT_INVULNERABILITY)) ||
   ((other.items & IT_QUAD) && (other.items & IT_INVULNERABILITY)))
   {
      bprint (other.netname);
      bprint (" has acquired all 3 powerups!\n");
   }


i'm sure there's a more elegant way to accomplish this, but that's just the first thing i thought of.... if anyone else has a better way, please share!

For the full test example, I was using this (in void() powerup_touch right before "if (deathmatch)")

Code: Select all
   if (((other.items & IT_INVISIBILITY) && (other.items & IT_QUAD)) ||
   ((other.items & IT_INVISIBILITY) && (other.items & IT_INVULNERABILITY)) ||
   ((other.items & IT_QUAD) && (other.items & IT_INVULNERABILITY)))
   {
      bprint (other.netname);
      bprint (" has acquired all 3 powerups!\n");
      other.invisible_time = 1;
      other.invisible_finished = time + 30;
      other.invincible_time = 1;
      other.invincible_finished = time + 30;
      other.super_time = 1;
      other.super_damage_finished = time + 30;
   }


so it basically just resets the timers so all three powerups end at exactly the same time. i tested it in dm3.bsp

thanks again for your help!
User avatar
dayfive
 
Posts: 77
Joined: Fri Nov 10, 2006 9:48 pm

Postby Preach » Fri Dec 01, 2006 3:33 pm

Currently the way you have it, the message will go off if the player has two of the three powerups and then touches any powerup. So if they got quad, then pent, then a second quad, the message would go off even though they only have those two powerups. What you could do is put the original check for all three powerups in, but put it further down in powerup_touch, specifically after the line

other.items = other.items | self.items;

At this point the player does have all three items, so you can do the check and it'll succeed.
Preach
 
Posts: 122
Joined: Thu Nov 25, 2004 7:20 pm

Postby dayfive » Fri Dec 01, 2006 3:46 pm

Preach wrote:Currently the way you have it, the message will go off if the player has two of the three powerups and then touches any powerup. So if they got quad, then pent, then a second quad, the message would go off even though they only have those two powerups. What you could do is put the original check for all three powerups in, but put it further down in powerup_touch, specifically after the line

other.items = other.items | self.items;

At this point the player does have all three items, so you can do the check and it'll succeed.


oh! i see... thanks for pointing this out! i tried your suggestion and it works as expected. i think i understand the concept much better than the first post in this thread.

thank you Preach and Quake Matt!
User avatar
dayfive
 
Posts: 77
Joined: Fri Nov 10, 2006 9:48 pm

Postby r00k » Sat Dec 02, 2006 6:15 am

in powerup_touch....
after other.items = other.items | self.item;
add...
Code: Select all
if (other.items & IT_INVISIBILITY | IT_INVULNERABILITY | IT_QUAD)
{
  other.invisible_time = other.invincible_time = other.super_time = 1;
  other.invisible_finished = other.invincible_finished = other.super_damage_finished = time + 30;       
}


:)
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Sajt » Sat Dec 02, 2006 4:46 pm

That'll detect if you have any one or more of them...

if ((other.items & IT_INVISIBILITY | IT_INVULNERABILITY | IT_QUAD) == IT_INVISIBILITY | IT_INVULNERABILITY | IT_QUAD)

would be the full solution, equivalent to Preach's solution

Might need more parentheses in there though, not sure.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Sajt
 
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am


Return to QuakeC Programming

Who is online

Users browsing this forum: No registered users and 1 guest