11-18-2011, 08:43 AM
I've been making improvements to my game Vore Tournament in the last days. Yesterday, I managed to get the weapon display working and indicating ammo properly. Since I believe this would be an awesome feature in Xonotic, I thought to share it here.
How it's done: VT is forked from Nexuiz, so it uses server-side entities even for the view model. Each display digit consists of a flat surface, which has the same center as v_weapon but with the mesh positioned to fit the screen. In-game, the weapon spawns all of its digits when you switch to it, the digits being removed once your weapon changes. Each digit is a separate entity, attached to the same origin as the gun model. divVerent suggested I add attachment tags to the weapon and put digits on that, but my md3 exporter doesn't handle this well so I made each digit separate.
Next up, each digit contains 11 skins, consisting of numbers 0 to 9 and an empty digit. Each digit knows the character it represents in the ammo string, and uses substring(ftos(self.(self.current_ammo)), blah, blah) to get the proper value. The number is next converted back into a float and self.skin set to it. If the string returns "" (happens when your ammo goes under 3 digits, like dropping from 110 to 90) then the blank texture is used. Otherwise 60 would show as 600 and so on. Digits are shown on both the view model and exterior weapon model, which means that if you're good enough you can see the ammo on your enemy's weapon... although in practice that's nearly impossible
Like I said, I'd adore to see this in Xonotic. Weapon displays rock, and I love how UT99 used to do it. Some weapons could have hologram displays too, with transparent numbers floating above a small device on the weapon. Since my game uses reloading by default, 2 digits show the weapon load and the other 3 ammo. Since most Xonotic guns use ammo directly, we'd only need 3 digits, showing ammo normally and weapon load if reloading is enabled for that gun.
Below are screenshots and a video of how this is done in VT (you can see the ammo on the weapon matches the one on the HUD). I'm also posting the code used by the digits, in case it's of any interest. This code is located at the bottom of cl_weaponsystem.qc right before void W_DecreaseAmmo. W_Display is called in w_*.qc in the (req == WR_SETUP) check, and is compatible with any weapon.
Let me know what you think about this, which weapons you believe this would look good on (and how), and what your ideas for implementation are. Note that divVerent is working on csqc models, which will certainly change how this needs to be implemented.
How it's done: VT is forked from Nexuiz, so it uses server-side entities even for the view model. Each display digit consists of a flat surface, which has the same center as v_weapon but with the mesh positioned to fit the screen. In-game, the weapon spawns all of its digits when you switch to it, the digits being removed once your weapon changes. Each digit is a separate entity, attached to the same origin as the gun model. divVerent suggested I add attachment tags to the weapon and put digits on that, but my md3 exporter doesn't handle this well so I made each digit separate.
Next up, each digit contains 11 skins, consisting of numbers 0 to 9 and an empty digit. Each digit knows the character it represents in the ammo string, and uses substring(ftos(self.(self.current_ammo)), blah, blah) to get the proper value. The number is next converted back into a float and self.skin set to it. If the string returns "" (happens when your ammo goes under 3 digits, like dropping from 110 to 90) then the blank texture is used. Otherwise 60 would show as 600 and so on. Digits are shown on both the view model and exterior weapon model, which means that if you're good enough you can see the ammo on your enemy's weapon... although in practice that's nearly impossible
Like I said, I'd adore to see this in Xonotic. Weapon displays rock, and I love how UT99 used to do it. Some weapons could have hologram displays too, with transparent numbers floating above a small device on the weapon. Since my game uses reloading by default, 2 digits show the weapon load and the other 3 ammo. Since most Xonotic guns use ammo directly, we'd only need 3 digits, showing ammo normally and weapon load if reloading is enabled for that gun.
Below are screenshots and a video of how this is done in VT (you can see the ammo on the weapon matches the one on the HUD). I'm also posting the code used by the digits, in case it's of any interest. This code is located at the bottom of cl_weaponsystem.qc right before void W_DecreaseAmmo. W_Display is called in w_*.qc in the (req == WR_SETUP) check, and is compatible with any weapon.
Code:
void W_DisplayDigitThink()
{
self.nextthink = time;
// the owner has switched to another weapon, remove the digits
if(self.weapon != self.owner.weapon)
{
self.nextthink = 0;
remove(self);
self = world;
return;
}
entity gun;
if(self.dmg) // exterior weapon
{
// keep the digit attached to the same bone as the gun
setattachment(self, self.owner, "bip01 r hand");
gun = self.owner.exteriorweaponentity;
}
else // view weapon
{
// keep the digit attached to the same bone as the gun
// TODO: Does this work with self-animated weapons too?
if(gettagindex(self.owner.weaponentity, "weapon"))
setattachment(self, self.owner.weaponentity, "weapon");
else if(gettagindex(self.owner.weaponentity, "tag_weapon"))
setattachment(self, self.owner.weaponentity, "tag_weapon");
gun = self.owner.weaponentity.weaponentity;
}
// copy all properties of the weapon to the digit
self.origin = gun.origin;
self.angles = gun.angles;
self.scale = gun.scale;
self.effects = gun.effects;
self.alpha = gun.alpha;
self.colormap = gun.colormap;
self.colormod = gun.colormod;
self.glowmod = gun.glowmod;
string txt;
if(self.team) // weapon load display
{
if(self.owner.weapon_load[self.owner.weapon] <= 0)
{
self.skin = 11; // unavailable digit
return;
}
else
{
txt = ftos(floor(self.owner.weapon_load[self.owner.weapon]));
txt = substring(txt, self.cnt - 1, 1);
}
}
else // ammo display
{
txt = ftos(floor(self.owner.(self.owner.current_ammo)));
txt = substring(txt, self.cnt - 1, 1);
}
if((!txt || txt == ""))
self.skin = 10; // empty digit
else
self.skin = stof(txt);
}
void W_DisplayDigitSetup(entity own, float num, float load, float exterior)
{
entity digit, e;
digit = spawn();
digit.owner = own;
digit.weapon = own.weapon;
digit.dmg = exterior;
digit.team = load;
digit.cnt = num;
e = get_weaponinfo(digit.weapon);
if(load)
{
// weapon load digit
setmodel(digit, strcat("models/weapons/v_", e.netname, "_digit1-", ftos(num) , ".md3"));
}
else
{
// ammo count digit
setmodel(digit, strcat("models/weapons/v_", e.netname, "_digit2-", ftos(num) , ".md3"));
}
digit.think = W_DisplayDigitThink;
digit.nextthink = time;
}
void W_Display(entity own, float load_num, float ammo_num)
{
float i;
for(i = 1; i <= load_num; i++)
{
W_DisplayDigitSetup(own, i, TRUE, FALSE); // weapon load digit, view model
W_DisplayDigitSetup(own, i, TRUE, TRUE); // weapon load digit, exterior model
}
for(i = 1; i <= ammo_num; i++)
{
W_DisplayDigitSetup(own, i, FALSE, FALSE); // ammo count digit, view model
W_DisplayDigitSetup(own, i, FALSE, TRUE); // ammo count digit, exterior model
}
}
Let me know what you think about this, which weapons you believe this would look good on (and how), and what your ideas for implementation are. Note that divVerent is working on csqc models, which will certainly change how this needs to be implemented.