Entity flags aren't being transmitted / cgame issues
Posted: Wed Jun 06, 2018 5:54 pm
Hello! I haven't been here in a while, but I've recently released the first version of a mod I've been working on called Uber Arena, which you can read about here: http://www.celephais.net/board/view_thread.php?id=61575
So the development of the mod has mostly been going pretty smooth so far, but I recently ran into a huge roadblock that's preventing me from implementing a very important visual clarity feature in the mod, and I've tried for 3 days coming up with various complicated attempted solutions that either don't work or present other issues.
This will be a lengthy post, so hopefully I've gotten all the relevant information in here. Anyway...
To start things off, the trademark mechanic of this mod is uberweapons, which work like this: you collect 3 of the same weapon without dying in between, and that weapon gets upgraded into its uberweapon version. The way this mechanic works in the code is that it uses a set of integer counters corresponding to each non-starter weapon, located in the gclient_s structure in g_local.h. Each time a weapon is picked up, that weapon's corresponding counter is incremented. Once the counter reaches 3, any uberweapon-specific functionality will start running. The uberweapons are not technically new, separate weapons - that would be impossible for me to do, because that would require defining 7 new weapons in weapon_t, which would exceed the MAX_WEAPONS limit of 16 as defined in q_shared.h - and of course I can't change that limit without totally screwing up the entire game. q_shared.h is pretty much untouchable for mods apart from a very few select sections.
Now, from a pure gameplay perspective, all of the uberweapon-related mechanics work just fine. But now I'm moving onto visual / audio coding, which of course involves doing a lot of work in cgame. To attempt to communicate with the client game, I defined 7 new entity flags in bg_public.h, which can be set in game and then - well, in theory anyway (more on that in a minute) - be read in cgame. Each time an uberweapon counter hits 3, the game will turn on the appropriate uberweapon flag with the intention of allowing cgame to know that the player has an uberweapon. Here are the flags and their values, respectively (they follow the hex notation format and sequencing as with the other eflags):
So when a player holds an uberweapon I want to draw a ring model with an energy orb shader that moves around the torso of the player. In theory, I should be able to do this by accessing EF_UW_SHOTGUN flag from cent->currentState.eFlags. I have the following code in the CG_Player function in cg_players.c:
Now, without the (cent->currentState.eFlags & EF_UW_SHOTGUN) in the if condition, the game does correctly respond to the player having the shotgun currently in use or not. So it can clearly read what player the weapon is using just fine. However, with the condition checking for the EF_UW_SHOTGUN flag, the code doesn't execute at all. I did a CG_Printf test of the value returned by (cent->currentState.eFlags & EF_UW_SHOTGUN) above the if statement and it returns 0 even if I have an uberweapon, proving that the cgame code isn't responding to the changes in cent->currentState.eFlags.
I tried several methods to get this to work. Then I wrote this code in the PmoveSingle function in bg_pmove.c and it somehow started working:
So this kind of works, but the problem is that only
I
have this effect (checking with cg_thirdperson 1). But if you look at another player who is currently using an uberweapon, the effect does not show up on them, even though they too should have those flags set. I tried messing with the renderfx settings like RF_THIRD_PERSON and RF_FIRST_PERSON, but none of those have worked. I don't know why, because there's this section of Team Arena code also in the CG_Player function that controls the floating skull heads that appear when a player has Kamikaze:
This isn't the full code, but you can still see that also relies on flags (EF_KAMIKAZE and EF_DEAD), and it works fine there. In Team Arena, if another player has Kamikaze - in other words, they have EF_KAMIKAZE enabled, you can see the floating skulls around them, and it also reacts appropriately if the player is dead. But in my mod, if another player has an uberweapon and its respective flag enabled, I can't see their uberweapon effect, only my own (from my point of view, in cg_thirdperson 1). Why does it work in the former case, and not in my case?
Here's another problem: Even though the CG_Player function can now read (cent->currentState.eFlags & EF_UW_SHOTGUN) because of the code I put in bg_pmove.c from earlier, it doesn't seem to be reflected everywhere in cgame. In cg_ents.c, in the CG_Missile function, it seems like it can't read cent->currentState.eFlags, even though CG_Player can. In this case I want homing rockets fired from an upgraded rocket launcher to play a beeping noise. As with EF_UW_SHOTGUN, I put the following code in PmoveSingle, right underneath the one for the shotgun:
And here is a snippet of the missile code, with my tracking code at the bottom:
It is perfectly capable of reading and retrieving values from its position and entity index (cent->currentState.pos and cent->currentState.number, respectively). However, it seems to completely ignore the entity flags I set for it (cent->currentState.eFlags & EF_UW_ROCKET). Why does it read the position / entity index properly, but not my flags? What's even stranger is that in CG_AddEntity, the function that calls CG_Missile, when I do a CG_Printf debug test to check the value of (cent->currentState.eFlags & EF_UW_ROCKET), it prints the int value of its hex constant, so it reads it properly there, just that for some reason it completely drops it when it gets passed into CG_Missile. And yes I tried stuff like assigning it to a boolean variable and passing it into CG_Missile (both by value and via a pointer to its address), but it always ends up coming out false after being passed, even if it was true in CG_AddEntity. Kind of defeats one of the main purposes of a function if it's just going to drop whatever I pass in, no?
This is a lot to take in, so I'll just summarize my goals here - I want to:
- Create a visual effect that displays on any player that is currently using an uberweapon.
- Make homing rockets play a targeting alert sound if they are fired by a player using a Homing Rocket Launcher.
Two goals that sound very simple to achieve in theory, but apparently are monstrously difficult in practice.
Thanks for any assistance in advance!
So the development of the mod has mostly been going pretty smooth so far, but I recently ran into a huge roadblock that's preventing me from implementing a very important visual clarity feature in the mod, and I've tried for 3 days coming up with various complicated attempted solutions that either don't work or present other issues.
This will be a lengthy post, so hopefully I've gotten all the relevant information in here. Anyway...
To start things off, the trademark mechanic of this mod is uberweapons, which work like this: you collect 3 of the same weapon without dying in between, and that weapon gets upgraded into its uberweapon version. The way this mechanic works in the code is that it uses a set of integer counters corresponding to each non-starter weapon, located in the gclient_s structure in g_local.h. Each time a weapon is picked up, that weapon's corresponding counter is incremented. Once the counter reaches 3, any uberweapon-specific functionality will start running. The uberweapons are not technically new, separate weapons - that would be impossible for me to do, because that would require defining 7 new weapons in weapon_t, which would exceed the MAX_WEAPONS limit of 16 as defined in q_shared.h - and of course I can't change that limit without totally screwing up the entire game. q_shared.h is pretty much untouchable for mods apart from a very few select sections.
Now, from a pure gameplay perspective, all of the uberweapon-related mechanics work just fine. But now I'm moving onto visual / audio coding, which of course involves doing a lot of work in cgame. To attempt to communicate with the client game, I defined 7 new entity flags in bg_public.h, which can be set in game and then - well, in theory anyway (more on that in a minute) - be read in cgame. Each time an uberweapon counter hits 3, the game will turn on the appropriate uberweapon flag with the intention of allowing cgame to know that the player has an uberweapon. Here are the flags and their values, respectively (they follow the hex notation format and sequencing as with the other eflags):
Code: Select all
#define EF_UW_SHOTGUN 0x01000000 // explosive shotgun
#define EF_UW_GRENADE 0x02000000 // multi grenade
#define EF_UW_ROCKET 0x04000000 // homing rocket
#define EF_UW_LIGHTNING 0x08000000 // arc lightning
#define EF_UW_PLASMA 0x10000000 // ion plasma
#define EF_UW_RAIL 0x20000000 // toxic rail
#define EF_UW_BFG 0x40000000 // bfg30k
Code: Select all
if (cent->currentState.weapon == WP_SHOTGUN && (cent->currentState.eFlags & EF_UW_SHOTGUN))
{
memcpy(&orbs, &torso, sizeof(torso));
orbs.hModel = cgs.media.uberShotgunOrbModel;
orbs.customSkin = 0;
VectorCopy(torso.origin, orbs.origin);
spinAngles[1] = cg.time * -0.2;
AnglesToAxis(spinAngles, orbs.axis);
trap_R_AddRefEntityToScene(&orbs);
}
I tried several methods to get this to work. Then I wrote this code in the PmoveSingle function in bg_pmove.c and it somehow started working:
Code: Select all
if (pm->ps->stats[STAT_UBERS] & UW_SHOTGUN)
{
pm->ps->eFlags |= EF_UW_SHOTGUN;
}


Code: Select all
if ( cent->currentState.eFlags & EF_KAMIKAZE )
{
memset( &skull, 0, sizeof(skull) );
VectorCopy( cent->lerpOrigin, skull.lightingOrigin );
skull.shadowPlane = shadowPlane;
skull.renderfx = renderfx;
if ( cent->currentState.eFlags & EF_DEAD ) {
// one skull bobbing above the dead body
angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;
if (angle > M_PI * 2)
angle -= (float)M_PI * 2;
dir[0] = sin(angle) * 20;
dir[1] = cos(angle) * 20;
angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
dir[2] = 15 + sin(angle) * 8;
VectorAdd(torso.origin, dir, skull.origin);
<goes on from here...>
Here's another problem: Even though the CG_Player function can now read (cent->currentState.eFlags & EF_UW_SHOTGUN) because of the code I put in bg_pmove.c from earlier, it doesn't seem to be reflected everywhere in cgame. In cg_ents.c, in the CG_Missile function, it seems like it can't read cent->currentState.eFlags, even though CG_Player can. In this case I want homing rockets fired from an upgraded rocket launcher to play a beeping noise. As with EF_UW_SHOTGUN, I put the following code in PmoveSingle, right underneath the one for the shotgun:
Code: Select all
if (pm->ps->stats[STAT_UBERS] & UW_ROCKET)
{
pm->ps->eFlags |= EF_UW_ROCKET;
}
Code: Select all
// add missile sound
if ( weapon->missileSound )
{
vec3_t velocity;
BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity );
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
// right below is my code
if (weapon->trackSound && cent->currentState.eFlags & EF_UW_ROCKET) {
trap_S_AddLoopingSound(cent->currentState.number, cent->lerpOrigin, velocity, weapon->trackSound);
}
}
This is a lot to take in, so I'll just summarize my goals here - I want to:
- Create a visual effect that displays on any player that is currently using an uberweapon.
- Make homing rockets play a targeting alert sound if they are fired by a player using a Homing Rocket Launcher.
Two goals that sound very simple to achieve in theory, but apparently are monstrously difficult in practice.
Thanks for any assistance in advance!