Improvement to standard backpack touch
Improvement to standard backpack touch
I have been wanting to do this one for a long time, but the proper plan sort of eludes me. Lets say theres a backpack from a fragged player that has (40) shells , (64) nails and (100) cells. The player touches it, and he already has (90) shells (40) nails and (0) Cells.
The ID code merely gives the player (100) shells, (100) nails and (100) cells, and the backpack disappears. I want the player to get the same ammo, but leave the backpack there containing what he cannot carry: (30) shells, (4) nails. Heres the touch function Im using, which I think is pretty much standard. Any help with some good code, or if anyone knows existing code to do this, thanks.
void () BackpackTouch =
{
local string s;
local float best;
local float old;
local float new;
local float bbest;
local entity stemp;
local float acount;
if (((other.classname != "player") && (other.classname != "bot")))
{
return;
}
if ((other.health <= 0))
{
return;
}
if (((other == self.owner) && ((self.nextthink - time) > 118)))
{
return;
}
acount = 0;
if ((cvar ("temp1") < 65535))
{
if ((other.classname == "player"))
{
sprint (other, "You get ");
}
}
stemp = self;
self = other;
best = W_BestWeapon ();
if (self.classname == "bot")
{
if (stemp.altname == "tossedpack")
fBotSayTeam (": Thanks.\n");
else if ((stemp.ammo_shells + stemp.ammo_nails) > 175 || (stemp.ammo_rockets + stemp.ammo_cells) > 100)
{
bprint (self.talkname);
bprint ("º ");
BotSayMiddle ("Nice Pack ");
if (stemp.owner.team != self.team)
BotSayMiddle (stemp.owner.netname);
BotSayEnd ();
}
}
self = stemp;
other.ammo_shells = (other.ammo_shells + self.ammo_shells);
other.ammo_nails = (other.ammo_nails + self.ammo_nails);
other.ammo_rockets = (other.ammo_rockets + self.ammo_rockets);
other.ammo_cells = (other.ammo_cells + self.ammo_cells);
new = self.items;
if (!new)
new = other.weapon;
old = other.items;
other.items = (other.items | new);
bound_other_ammo ();
if ((other.classname == "player"))
{
if ((cvar ("temp1") < 65535))
{
if (self.ammo_shells)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_shells);
sprint (other, s);
sprint (other, " shells");
}
if (self.ammo_nails)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_nails);
sprint (other, s);
sprint (other, " nails");
}
if (self.ammo_rockets)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_rockets);
sprint (other, s);
sprint (other, " rockets");
}
if (self.ammo_cells)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_cells);
sprint (other, s);
sprint (other, " cells");
}
sprint (other, "\n");
stuffcmd (other, "bf\n");
}
}
if (((deathmatch & DM_START_SMALL) || (deathmatch & DM_START_BIG)))
{
other.health = (other.health + 5);
}
sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, SUB_Db());
remove (self);
self = other;
if ((other.classname == "player"))
{
if ((WeaponCode (new) <= other.best_wep))
{
if ((self.flags & FL_INWATER))
{
if ((new != IT_LIGHTNING))
{
Deathmatch_Weapon (old, new);
}
}
else
{
Deathmatch_Weapon (old, new);
}
}
}
else
{
Deathmatch_Weapon (old, new);
}
W_SetCurrentAmmo ();
};
The ID code merely gives the player (100) shells, (100) nails and (100) cells, and the backpack disappears. I want the player to get the same ammo, but leave the backpack there containing what he cannot carry: (30) shells, (4) nails. Heres the touch function Im using, which I think is pretty much standard. Any help with some good code, or if anyone knows existing code to do this, thanks.
void () BackpackTouch =
{
local string s;
local float best;
local float old;
local float new;
local float bbest;
local entity stemp;
local float acount;
if (((other.classname != "player") && (other.classname != "bot")))
{
return;
}
if ((other.health <= 0))
{
return;
}
if (((other == self.owner) && ((self.nextthink - time) > 118)))
{
return;
}
acount = 0;
if ((cvar ("temp1") < 65535))
{
if ((other.classname == "player"))
{
sprint (other, "You get ");
}
}
stemp = self;
self = other;
best = W_BestWeapon ();
if (self.classname == "bot")
{
if (stemp.altname == "tossedpack")
fBotSayTeam (": Thanks.\n");
else if ((stemp.ammo_shells + stemp.ammo_nails) > 175 || (stemp.ammo_rockets + stemp.ammo_cells) > 100)
{
bprint (self.talkname);
bprint ("º ");
BotSayMiddle ("Nice Pack ");
if (stemp.owner.team != self.team)
BotSayMiddle (stemp.owner.netname);
BotSayEnd ();
}
}
self = stemp;
other.ammo_shells = (other.ammo_shells + self.ammo_shells);
other.ammo_nails = (other.ammo_nails + self.ammo_nails);
other.ammo_rockets = (other.ammo_rockets + self.ammo_rockets);
other.ammo_cells = (other.ammo_cells + self.ammo_cells);
new = self.items;
if (!new)
new = other.weapon;
old = other.items;
other.items = (other.items | new);
bound_other_ammo ();
if ((other.classname == "player"))
{
if ((cvar ("temp1") < 65535))
{
if (self.ammo_shells)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_shells);
sprint (other, s);
sprint (other, " shells");
}
if (self.ammo_nails)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_nails);
sprint (other, s);
sprint (other, " nails");
}
if (self.ammo_rockets)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_rockets);
sprint (other, s);
sprint (other, " rockets");
}
if (self.ammo_cells)
{
if (acount)
{
sprint (other, ", ");
}
acount = WEAPON_SHOTGUN;
s = ftos (self.ammo_cells);
sprint (other, s);
sprint (other, " cells");
}
sprint (other, "\n");
stuffcmd (other, "bf\n");
}
}
if (((deathmatch & DM_START_SMALL) || (deathmatch & DM_START_BIG)))
{
other.health = (other.health + 5);
}
sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, SUB_Db());
remove (self);
self = other;
if ((other.classname == "player"))
{
if ((WeaponCode (new) <= other.best_wep))
{
if ((self.flags & FL_INWATER))
{
if ((new != IT_LIGHTNING))
{
Deathmatch_Weapon (old, new);
}
}
else
{
Deathmatch_Weapon (old, new);
}
}
}
else
{
Deathmatch_Weapon (old, new);
}
W_SetCurrentAmmo ();
};
Sorry, the lack of formatting is making it impossible for me to even read.
Benjamin Darling
http://www.bendarling.net/
Reflex - In development competitive arena fps combining modern tech with the speed, precision and freedom of 90's shooters.
http://www.reflexfps.net/
http://www.bendarling.net/
Reflex - In development competitive arena fps combining modern tech with the speed, precision and freedom of 90's shooters.
http://www.reflexfps.net/
doesn't using the
Code: Select all
bbcode fix this?
You will want to modify two different parts of the touch function to make the intended change possible.
Part I:
Part II:
Part I notes:
Imagine that the player had 90 shotgun shells and grabbed a large box (40 shells). The player's .ammo_shells would be 130. Id's BackpackTouch() already does this to the player and then uses bound_other_ammo() to cap it. Let's set the player's ammo the same way, but afterward shave the top off and assign it to the backpack. In this case, the backpack should be left with 30 shells (130 on player - 100 limit = 30).
As the player may have needed all ammo of a given type, remember to check for that and set the relevant ammo count on the backpack to 0. Otherwise the backpack will become an endless supply of ammo.
You will also need to make some changes to the way the "You got ..." messages are generated, since the player can now trigger the touch function without it actually giving the player anything. This is a bit more complicated, so I have provided a full solution below.
Part II notes:
Backpacks are removed when they are touched by players. You will want to remove it only if it is empty. I suggest borrowing the line in DropBackPack() that checks this.
Example / Spoilers
To fix the display, I defined 4 local variables to hold the precise ammo count given to the player. I added a check to see if the backpack would need to generate a message and to exit the touch if not. I moved the weapon check after the ammo stuff to make that check possible. Though I didn't add your new functions to it, feel free to do so!
Edit: the same logic now applies to weapons in backpacks (remove weapon if taken).
Edit 2: was exhausted when writing previous edit. My previous mistake has been corrected.
Part I:
Code: Select all
other.ammo_shells = (other.ammo_shells + self.ammo_shells);
other.ammo_nails = (other.ammo_nails + self.ammo_nails);
other.ammo_rockets = (other.ammo_rockets + self.ammo_rockets);
other.ammo_cells = (other.ammo_cells + self.ammo_cells);
new = self.items;
if (!new)
new = other.weapon;
old = other.items;
other.items = (other.items | new);
bound_other_ammo ();
Code: Select all
remove(self);
self = other;
Part I notes:
Imagine that the player had 90 shotgun shells and grabbed a large box (40 shells). The player's .ammo_shells would be 130. Id's BackpackTouch() already does this to the player and then uses bound_other_ammo() to cap it. Let's set the player's ammo the same way, but afterward shave the top off and assign it to the backpack. In this case, the backpack should be left with 30 shells (130 on player - 100 limit = 30).
Code: Select all
other.ammo_shells = (other.ammo_shells + self.ammo_shells);
if (other.ammo_shells > 100)
self.ammo_shells = other.ammo_shells - 100;
Code: Select all
else
self.ammo_shells = 0;
Part II notes:
Backpacks are removed when they are touched by players. You will want to remove it only if it is empty. I suggest borrowing the line in DropBackPack() that checks this.
Code: Select all
if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells))
remove(self);
Example / Spoilers
To fix the display, I defined 4 local variables to hold the precise ammo count given to the player. I added a check to see if the backpack would need to generate a message and to exit the touch if not. I moved the weapon check after the ammo stuff to make that check possible. Though I didn't add your new functions to it, feel free to do so!
Edit: the same logic now applies to weapons in backpacks (remove weapon if taken).
Edit 2: was exhausted when writing previous edit. My previous mistake has been corrected.
Code: Select all
void() BackpackTouch =
{
local float old, new;
local float acount;
local float taken_shells, taken_nails, taken_rockets, taken_cells, taken_item;
if (other.classname != "player")
return;
if (other.health <= 0)
return;
acount = 0;
other.ammo_shells = (other.ammo_shells + self.ammo_shells);
taken_shells = self.ammo_shells;
if (other.ammo_shells > 100)
{
self.ammo_shells = other.ammo_shells - 100;
other.ammo_shells = 100;
}
else
self.ammo_shells = 0;
taken_shells = taken_shells - self.ammo_shells;
other.ammo_nails = (other.ammo_nails + self.ammo_nails);
taken_nails = self.ammo_nails;
if (other.ammo_nails > 200)
{
self.ammo_nails = other.ammo_nails - 200;
other.ammo_nails = 200;
}
else
self.ammo_nails = 0;
taken_nails = taken_nails - self.ammo_nails;
other.ammo_rockets = (other.ammo_rockets + self.ammo_rockets);
taken_rockets = self.ammo_rockets;
if (other.ammo_rockets > 100)
{
self.ammo_rockets = other.ammo_rockets - 100;
other.ammo_rockets = 100;
}
else
self.ammo_rockets = 0;
taken_rockets = taken_rockets - self.ammo_rockets;
other.ammo_cells = (other.ammo_cells + self.ammo_cells);
taken_cells = self.ammo_cells;
if (other.ammo_cells > 100)
{
self.ammo_cells = other.ammo_cells - 100;
other.ammo_cells = 100;
}
else
self.ammo_cells = 0;
taken_cells = taken_cells - self.ammo_cells;
old = other.weapon;
if (self.items)
{
if ((other.items & self.items) == 0)
{
new = self.items;
other.items = (other.items | new);
self.items = 0;
taken_item = 3;
}
}
if (!new)
new = other.weapon;
//don't do the screen flash or generate a message unless necessary
//Don't bother players with messages, sound, or screenflash when they choose to stand
//on a backpack.
if ((taken_shells + taken_nails + taken_rockets + taken_cells + taken_item) > 2)
{
sprint (other, "You get ");
if (taken_item)
{
acount = 1;
sprint (other, "the ");
sprint (other, self.netname);
}
if (taken_shells)
{
if (acount)
sprint(other, ", ");
acount = 1;
s = ftos(taken_shells);
sprint (other, s);
sprint (other, " shells");
}
if (taken_nails)
{
if (acount)
sprint(other, ", ");
acount = 1;
s = ftos(taken_nails);
sprint (other, s);
sprint (other, " nails");
}
if (taken_rockets)
{
if (acount)
sprint(other, ", ");
acount = 1;
s = ftos(taken_rockets);
sprint (other, s);
sprint (other, " rockets");
}
if (taken_cells)
{
if (acount)
sprint(other, ", ");
acount = 1;
s = ftos(taken_cells);
sprint (other, s);
sprint (other, " cells");
}
sprint (other, "\n");
// backpack touch sound and screen effect
sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
stuffcmd (other, "bf\n");
}
// remove the backpack if it has no ammo
if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells))
remove(self);
// change to the weapon if it was taken.
self = other;
if (!deathmatch)
self.weapon = new;
else
Deathmatch_Weapon (old, new);
if (old != self.weapon)
W_SetCurrentAmmo ();
else
{
//mini W_SetCurrentAmmo()
//previous weapon and current weapon are the same.
//Just update the HUD; don't do weapon switch pause.
if (self.weapon == IT_SHOTGUN)
self.currentammo = self.ammo_shells;
else if (self.weapon == IT_SUPER_SHOTGUN)
self.currentammo = self.ammo_shells;
else if (self.weapon == IT_NAILGUN)
self.currentammo = self.ammo_nails;
else if (self.weapon == IT_SUPER_NAILGUN)
self.currentammo = self.ammo_nails;
else if (self.weapon == IT_GRENADE_LAUNCHER)
self.currentammo = self.ammo_rockets;
else if (self.weapon == IT_ROCKET_LAUNCHER)
self.currentammo = self.ammo_rockets;
else if (self.weapon == IT_LIGHTNING)
self.currentammo = self.ammo_cells;
else
self.currentammo = 0;
}
};
Last edited by lurker on Sat Jun 20, 2009 11:29 pm, edited 1 time in total.
Hey, thanks!
I also worked on some new code of my own but had problems with
the leftover ammo never dispensing. So I commented it all out and tried your code, which is a huge step forward.
Its really nice, but one thing that needs fixing is if you stand over the backpack and are firing the shotgun with 100 shells in your gun, you hear the guncock from the pack and you take a shell from the pack every time. Im thinking self.attack_finished needs to be put in there to prevent this from happening.
Another thing is that when you get craning with alot of frags, you wind up with many of these 'lesser' value ammo packs with shells laying around. So Im thinking to shorten the time do remove(self) happens quicker when more than 1 touch happens.
Also I noticed that sometimes you can touch a pack and get its (extra) shells, and one time I got the grenade launcher , with no grenades....which is kool, but I want to check the code again and make sure its giving up the weapon and deducting it from the pack so when its touched again, the weapon is not given again. Maybe you can tell me if that is working?
I also worked on some new code of my own but had problems with
the leftover ammo never dispensing. So I commented it all out and tried your code, which is a huge step forward.
Its really nice, but one thing that needs fixing is if you stand over the backpack and are firing the shotgun with 100 shells in your gun, you hear the guncock from the pack and you take a shell from the pack every time. Im thinking self.attack_finished needs to be put in there to prevent this from happening.
Another thing is that when you get craning with alot of frags, you wind up with many of these 'lesser' value ammo packs with shells laying around. So Im thinking to shorten the time do remove(self) happens quicker when more than 1 touch happens.
Also I noticed that sometimes you can touch a pack and get its (extra) shells, and one time I got the grenade launcher , with no grenades....which is kool, but I want to check the code again and make sure its giving up the weapon and deducting it from the pack so when its touched again, the weapon is not given again. Maybe you can tell me if that is working?
I was exhausted when adding the weapon check and I think I introduced a bug. I have rewritten the whole section while addressing another of your concerns. Due to its length, the updated version appears at the end of my previous post.
The weapon pickup/guncock sound no longer plays if the player is standing on a backpack while attacking. The player's ammo count continues to be updated as long as he or she stands on the backpack. I chose this in favor of setting .attack_time in case two players were both attempting to grab a backpack at the same time: if there is spare ammo, it wouldn't be fair to prevent the second player from grabbing it since the backpack is still clearly present.
In standard progs.dat, grabbing backpacks interrupts the player's current attack. I modified this to only interrupt the attack if the player's weapon has been changed by the backpack.
I agree: this sort of backpack_touch does leave too many backpacks in play. The quickest way to address this is to lower the timer in the following line of DropBackpack() :
The weapon pickup/guncock sound no longer plays if the player is standing on a backpack while attacking. The player's ammo count continues to be updated as long as he or she stands on the backpack. I chose this in favor of setting .attack_time in case two players were both attempting to grab a backpack at the same time: if there is spare ammo, it wouldn't be fair to prevent the second player from grabbing it since the backpack is still clearly present.
In standard progs.dat, grabbing backpacks interrupts the player's current attack. I modified this to only interrupt the attack if the player's weapon has been changed by the backpack.
I agree: this sort of backpack_touch does leave too many backpacks in play. The quickest way to address this is to lower the timer in the following line of DropBackpack() :
Code: Select all
item.nextthink = time + 120; // remove after 2 minutes
Looks interesting, gonna try it. I noticed you got rid of stemp = self and stemp = self. I never knew why they did that in much of the original code, it seems precautionary. All the code I ever wrote, I never needed to do that. The timer deduction for remove(self) is clever...I am using a .specific to count up to 4 each time the pack is touched, then it removes self. I may add something that detects if the pack contains only shells at spawn, make the timer about half or less than the default, to help lessen the number of packs laying around on the map.
-
- Posts: 2126
- Joined: Sat Nov 25, 2006 1:49 pm
Setting the time according the content looks a good idea IMO. Backpacks holding only a few shells last 20 or 30 seconds, but one containing a rocket launcher deserves to survive for 2 minutes.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC (LordHavoc)
Ok, finally got your code working with mine ! I used your ammo calculations as they seem to be flawless. I redid the 'you get' sprint, and of course the bf and sound so that it happens only when we have 'taken' something. Still got a bug with the comma popping up when you get just nails, rockets or cells, but it ought to be easy to fix. I took your advise and shortened the nextthink time by 15 if all we have are shells. Lot less packs floating around now.
Its amazing how one change like this alters gameplay for the bots. They have a tendency to hang around the ammo packs now, which seems to make gameplay a little more smoother and fun. It felt like a real CTF game.
Its amazing how one change like this alters gameplay for the bots. They have a tendency to hang around the ammo packs now, which seems to make gameplay a little more smoother and fun. It felt like a real CTF game.