cuteunit@Posted: Wed Jul 02, 2008 7:47 am :
I've tried. I've tried so hard. So very hard.

And I've had no success.

in Multiplayer the game seems to rotate who is the "owner" produced by getOwner(); called from the gun itself. In addition, GUI parms called by setGUIParm seem to be affecting all instances of the gui, across every gun, based on who Owner is this very second ( like I said it seems to keep changing..). Example is that I have a guiparm of "isfiring" that should pop up a gui element to hide the radar during fire... it comes up if player 1 shoots, on both player1 and player2's screens.

I really don't know whats going on. my ai_monster_base is building the key list tabe for the monsters from state::begin and setting the keys on $world, and the gun is checking from there.

I have like sixty hours and two sleepless nights trying to figure this out, and I dont think this is something I can solve with hard work anymore.. I need knowledge I dont have and the worthless completeley absent travesty of a lack of documentation that is id dev net and ( to a smaller extent, but I'm glad it's there) modwiki arent illuminating things for me..

*weeeeeeeeeeeeeeeeeep*

Anyways here is the code I'm using right now in weapon_plasmagun.script. Dont mind the mess... think of it as fingerpainting, I want it to work first then be aesthetic later. Some bits in the firing code are lifted from the chaingun to further confuse things I guess.

heeeeelp....
Code:
/***********************************************************************

weapon_plasmagun.script

***********************************************************************/

#define PLASMAGUN_FIRERATE         0.225 //changed by Tim
#define PLASMAGUN_LOWAMMO         10
#define PLASMAGUN_NUMPROJECTILES   2

// blend times
#define PLASMAGUN_IDLE_TO_LOWER      4
#define PLASMAGUN_IDLE_TO_FIRE      1
#define   PLASMAGUN_IDLE_TO_RELOAD   4
#define PLASMAGUN_RAISE_TO_IDLE      4
#define PLASMAGUN_FIRE_TO_IDLE      4
#define PLASMAGUN_RELOAD_TO_IDLE   4
#define   PLASMAGUN_CHAMBER_SPEED      ( 30 * ( GAME_FPS / 6 ) )
#define   PLASMAGUN_CHAMBER_ACCEL_TIME   0.5
#define PLASMAGUN_CHAMBER_DECCEL_TIME   2.0
#define   PLASMAGUN_CHAMBER_ACCEL      ( PLASMAGUN_CHAMBER_SPEED / PLASMAGUN_CHAMBER_ACCEL_TIME )
#define PLASMAGUN_CHAMBER_DECCEL      ( PLASMAGUN_CHAMBER_SPEED / PLASMAGUN_CHAMBER_DECCEL_TIME )

object weapon_plasmagun : weapon_base {
   float      next_attack;
   float      spread;
   float      current_rate;
   float      start_rate;
   float      end_rate;
   float      spin_start;
   float      spin_end;
   float       repCounter;
   float       stability;
   float       runonce;
   void      init();
   void      SpinUp();
   void      SpinDown();
   void      Lower();
   void      Raise();
   void      Idle();
   void      Fire();
   void      Reload();
   void      ExitCinematic();
   entity owner;
};

void weapon_plasmagun::init() {

   next_attack = 0;
   current_rate   = 0;
   start_rate      = 0;
   end_rate      = 0;
   spin_start      = 0;
   spin_end      = 0;
   spread      = 0.5;
   owner = getOwner();
   sys.println(" I set owner to "+owner.getName());
   repCounter = 0;
   weaponState( "Raise", 0 );
}
void weapon_plasmagun::UpdateChamber() {
   float currentTime;
   float t;
   vector ang;
   currentTime = sys.getTime();
   if ( currentTime < spin_end ) {
      t = ( currentTime - spin_start ) / ( spin_end - spin_start );
      current_rate = start_rate + t * ( end_rate - start_rate );
   } else {
      current_rate = end_rate;
   }
   string ownermotion = owner.getAnimState(ANIMCHANNEL_LEGS);
   if(ownermotion == "Legs_Crouched" || ownermotion == "Legs_CrouchWalk" || ownermotion == "Legs_CrouchWalk_Backward")
   {
      stability = 1;
   }
   else
   {
      stability = 0;
   }
   if (stability == 1)
   {
   setGuiParm("ownerstability", 1);
   }
   else
   {
   setGuiParm("ownerstability", 0);
   }
   //setGuiParm("chambercharge",current_rate);
}

void weapon_plasmagun::destroy() {

   stopSound( SND_CHANNEL_WEAPON, 1 );
   clearPersistantArgs();

}
void weapon_plasmagun::Raise() {

   weaponRising();
   setGuiParm("isFiring", 0);
   setGuiParm("productplacement",1);
   playAnim( ANIMCHANNEL_ALL, "raise" );
   waitUntil( animDone( ANIMCHANNEL_ALL, PLASMAGUN_RAISE_TO_IDLE ) );
   setGuiParm("productplacement",0);
   weaponState( "Idle", PLASMAGUN_RAISE_TO_IDLE );
}

void weapon_plasmagun::Lower() {
   weaponLowering();
   setGuiParm("productplacement",1);
   playAnim( ANIMCHANNEL_ALL, "putaway" );
   waitUntil( animDone( ANIMCHANNEL_ALL, 0 ) );
   weaponHolstered();
   waitUntil( WEAPON_RAISEWEAPON );
   weaponState( "Raise", 0 );
}
void weapon_plasmagun::SpinUp() {
   start_rate = current_rate;
   end_rate = PLASMAGUN_CHAMBER_SPEED;
   spin_start = sys.getTime();
   spin_end = spin_start + ( end_rate - current_rate ) / PLASMAGUN_CHAMBER_ACCEL;
   startSound( "snd_windup", SND_CHANNEL_BODY3, 1 );
}
void weapon_plasmagun::SpinDown() {
   start_rate = current_rate;
   end_rate = 0;
   spin_start = sys.getTime();
   spin_end = spin_start + ( current_rate - end_rate ) / PLASMAGUN_CHAMBER_DECCEL;
   startSound( "snd_winddown", SND_CHANNEL_BODY3, 1 );
}



void weapon_plasmagun::Idle() {

   float currentTime;
   float ammoClip;
   float avail;
   float clip_size;

   string monsterstate;
   clip_size = clipSize();   
   
   if ( !ammoInClip() ) {
      weaponOutOfAmmo();
   } else {
      weaponReady();
   }

      if (spread >0.5)
      {
         spread = 0.5;
      }

   // Added by radar mod   
   // The following is only updated every 10 frames, or 6 times a second, to save time.  repCounter tracks this.
   float repCounter = 0;
   while( 1 ) {


      repCounter++;
      if(repCounter >= 120) {
         repCounter = 0;
         sys.println (owner.getName() + " is owner called this pass");         
         // numBlips = number of blips currently on the radar.  If we hit the max (10) it immediately stops checking creatures.  It does NOT keep those closest; this would be more computationally intensive than I care to do.
         float numBlips = 0;
         // Location/rotation of player
         vector ppos = owner.getViewAngles();
         float pr = ppos_y+180;
         ppos = owner.getWorldOrigin();
         // The following 360->180 is from doom_util.script - it moves from a -180 -> 180 degree system to a 0 -> 360 degree system.
         while( pr < 0 ) {
            pr += 360;
         }
         while( pr >= 360 ) {
            pr -= 360;
         }
         float loop;
         float lpLim = $world.getFloatKey("monsterNum");
         // This loop steps through all the creatures that have registered themselves with the player during their Init()
         // If we hit 10 blips, it cancels out of the list early.

         for(loop = 1; loop <= lpLim && numBlips < 10; loop++)
         {
            entity monsterPointer = sys.getEntity($world.getKey("monsterList" + loop));//old hopefully can obsolete this
//            entity monsterPointer = sys.getEntity(sys.getPersistantString("monsterList"+loop));
            // If creature is dead or no longer existant, do nothing - oh, my kingdom for a linked list!
            // Condition also fails if radar is full
            entity monsterfoe = monsterPointer.getEnemy();
            string monstermoving = monsterfoe.getName(); //monsterPointer.getAnimState(ANIMCHANNEL_TORSO);
            // string monstermovingCA= monsterPointer.getName() +"::state_Begin";
            if(monsterPointer.getHealth() > 0 && monstermoving != "")
            {
   
                  // Location of this creature
                  vector blipLoc = monsterPointer.getWorldOrigin();
                  blipLoc = ppos-blipLoc;
                  // dt = distance between player and creature
                  float dt = sys.vecLength(blipLoc);
                  // Test for distance from player
                  if(dt <= 800 )
                  {

                     blipLoc = sys.VecToAngles(blipLoc);
                     // dr = difference of angle, in degrees, between current player facing and creature direction
                     float dr = blipLoc_y - pr;
                     // Creatures behind the player (or directly to either side) don't show up on the radar
                     // Technically, clipping in the GUI will take care of this anyway, but I worry about passing obscenely large values to the gui rect command.  Plus, it saves us unecessary calls to sin/cos.
                     // The dx1/dy1, dx2/dy2, etc. generated here are pixel locations for the gun GUI blips.  A value of -1 in either will result in the GUI hiding the blip altogether.
                     if(dr > -85 && dr < 85)
                     {
                     // Increment blip counter
                     numBlips++;
                     // Uncomment the following lines to get full, real-time info on creatures on the radar.
                     //sys.println("monsterPointer #" + numBlips + ": " + monsterPointer.getName() + "(" + dt + "units away)");
                     //sys.println("  rotation: " + dr + "  |  radar x/y: " + (274+(dt/3)*sys.cos(dr+90)) + " / " + (349-(dt/3)*sys.sin(dr+90)));
                     // Convert data to usable pixel locations on radar GUI
                     //sys.println(monstermoving);
                     //sys.println(monstermovingCA + " Is comparison");
                     setGuiParm("dx" + numBlips, 274+(dt/3)*sys.cos(dr+90)); //was 274
                     setGuiParm("dy" + numBlips, 349-(dt/3)*sys.sin(dr+90)); //was 349
                     }
                  }
               }
         
      }
         // Sets all coords for unusued blips to -1 so that the GUI hides them
         while(numBlips < 10) {
            numBlips++;
            //sys.println("Deadblip: " + numBlips);
            setGuiParm("dx" + numBlips, -1);
            setGuiParm("dy" + numBlips, -1);
         }
         //sys.println("----");
      }
      // End added by radar mod
      if ( WEAPON_LOWERWEAPON ) {
         weaponState( "Lower", PLASMAGUN_IDLE_TO_LOWER );
      }
      currentTime = sys.getTime();
      ammoClip = ammoInClip();
      if ( ( currentTime >= next_attack ) && WEAPON_ATTACK ) {
         if ( ammoClip > 0 ) {
            weaponState( "Fire", PLASMAGUN_IDLE_TO_FIRE );
         } else if ( ammoAvailable() > 0 ) {
            if ( autoReload() ) {
               netReload();
               weaponState( "Reload", PLASMAGUN_IDLE_TO_RELOAD );
            }
         }
      }
      if ( WEAPON_RELOAD && ( ammoAvailable() > ammoClip ) && ( ammoClip < clip_size ) ) {
         netReload();
         weaponState( "Reload", PLASMAGUN_IDLE_TO_RELOAD );
      }
      if ( WEAPON_NETRELOAD ) {
         WEAPON_NETRELOAD = false;
         weaponState( "Reload", PLASMAGUN_IDLE_TO_RELOAD );         
      }

      UpdateChamber();
      waitFrame();
   }
}



void weapon_plasmagun::Fire() {
   float ammoClip;
   float currentTime;
   float skip;
   float accuratecount;
   SpinUp();

   setGuiParm("isFiring", 1);// bring up GUI element to hide tracker.. just aesthetics
   ammoClip = ammoInClip();
   currentTime = sys.getTime(); // - overheat_count;

   while( ( current_rate < end_rate ) && !WEAPON_RELOAD && ( WEAPON_NETFIRING || ( WEAPON_ATTACK && ( ammoClip > 0 ) ) ) ) {
      UpdateChamber();
      waitFrame();
      ammoClip = ammoInClip();
   }
   startSound( "snd_fire", SND_CHANNEL_WEAPON, 1 );
   ammoClip = ammoInClip();
   while ( !WEAPON_RELOAD && ( WEAPON_NETFIRING || ( WEAPON_ATTACK && ( ammoClip > 0 ) ) ) ) {
      if (spread <20.0)
      {

         //sys.println(ownermotion);
         if( stability == 1)
         {
            spread = spread;
         }
         else
            {

            spread = spread *1.5;
            }
      }
      launchProjectiles( 1, spread, 0, 1.0, 1.0 );
//      startSound( "snd_fire", SND_CHANNEL_WEAPON, false );
      ammoClip = ammoInClip();

      if ( ammoClip == PLASMAGUN_LOWAMMO ) {
      startSound( "snd_lowammo", SND_CHANNEL_ITEM, true );
      }
      for( skip = 0; skip < 6; skip++ ) {
         UpdateChamber();
         waitFrame();
      }
      
   }
   
   stopSound( SND_CHANNEL_WEAPON, 1 );
   SpinDown();
   setGuiParm("isFiring", 0);
   weaponState( "Idle", PLASMAGUN_FIRE_TO_IDLE );
}

void weapon_plasmagun::Reload() {
   weaponReloading();
   playAnim( ANIMCHANNEL_ALL, "reload" );
   waitUntil( animDone( ANIMCHANNEL_ALL, PLASMAGUN_RELOAD_TO_IDLE ) );
   addToClip( clipSize() );
   weaponState( "Idle", PLASMAGUN_RELOAD_TO_IDLE );
}

void weapon_plasmagun::ExitCinematic() {
   current_rate   = 0;
   start_rate      = 0;
   end_rate      = 0;
   spin_start      = 0;
   spin_end      = 0;
   weaponState( "Idle", 0 );
}



cuteunit@Posted: Wed Jul 02, 2008 8:00 am :
Image

the gui I made.. it works well and looks nice I think.. and I should add that if there is only ONE PLAYER on the server, the code listed above works without flaw and delivers all expected functionality. It only goes to pooch when there's more than one player :(

I dont understand and am horribly depressed :(

(trying to use this with opencoop btw)



lowdragon@Posted: Wed Jul 02, 2008 11:18 am :
Hmmm, i just started scripting so iam not of a big help here but i had something similar with my q3mod which its origin was the networking. I guess i fixed it with something like "owner->self" or by giving each player a number.

hth, low



cuteunit@Posted: Wed Jul 02, 2008 12:07 pm :
Any more detail than that?



lowdragon@Posted: Wed Jul 02, 2008 1:54 pm :
My guess is you apparently sharing info you shouldnt and dont want to share, however thats how the game handels player info. So you need to verify playerinfo before sending them or dont send em at all - i dont know why it isnt part of the code in the first place, since you need the real player info (position) for the "blip" anyway.



wal@Posted: Wed Jul 02, 2008 3:39 pm :
That looks nice. I think this is just because you need to distinguish between the different players. They're all using owner so it will keep changing. You need owner1, owner2 etc and a way of distinguishing them. This is off the top of my head but something like this might work.
Code:
if ( owner.getKey( "name" ) == player2 ) {
   entity owner2 = getOwner();
}



Ivan_the_B@Posted: Wed Jul 02, 2008 9:21 pm :
Quote:
in Multiplayer the game seems to rotate who is the "owner" produced by getOwner(); called from the gun itself.

Are you sure? It seems very odd...
May be what you see printed in the console is from different players holding a plasmagun.

Quote:
GUI parms called by setGUIParm seem to be affecting all instances of the gui,

Yes, it works in that way for every gui, including the hud.
Don't know in multiplayer... it should be like default weapons guis. They are the same gui for every player but shows different values. :?



cuteunit@Posted: Thu Jul 03, 2008 2:55 am :
How can I provide provisions in the code to make this work in multi then? Particularly if the guis are being shared..

ugh, stupid system. So cool but so stupid.



cuteunit@Posted: Thu Jul 03, 2008 6:05 pm :
:(



Ivan_the_B@Posted: Thu Jul 03, 2008 7:20 pm :
sorry, but I 've never even touched D3 multiplayer. :?
You should
1) understand how to use not shared guis on weapons.
It's odd that it works this way... for example BFG script sets a GuiParm on the weapon. But in multiplayer it only affects your own weapon, doesn't it?

2) understand how get a list of all the players...
It's seems absurd that getOwner gives you every time a different result. You are probably observing in the cosole the results of all the instances of the scriptobject (1 for every player holding that weapon).

:?



cuteunit@Posted: Fri Jul 04, 2008 6:54 am :
the BFG weaponscript doesn't seem to do anything differrently to what I do in my weapon. It calls setGuiParm just like I do.

However I do not understand why it works there and not in my script. For example, my script checks the animstate of the owner's legs (checked from getOwner()) to see if he's crouching, to modify the spread of the weapon and to set a variable to true. If it's true, I set a gui parm named "stabilized" to 1, if it is not true, I set it back to 0.. and I check this prettymuch anytime the gun is doing anything.

in multiplayer, whenever the hosting player crouches ( if both the host and player 2 have a modded plasmagun) then the stabilized parm is getting set on BOTH of their weapons, unhiding the GUI element it's tied to. I don't understand it.

On top of this, the blips don't work for player 2 AT ALL. only player 1



simulation@Posted: Fri Jul 04, 2008 7:17 am :
Instead of using getOwner() in "::init()" and caching the value, try using
Code:
entity owner = getOwner();
in each method where you need it. In MP the weapon/owner relationship is synced in the netcode and you may be caching the wrong thing.



cuteunit@Posted: Sat Jul 05, 2008 9:01 am :
Tried that first, actually. Was doing that exact thing, in Idle and in Fire

Same effect.



cuteunit@Posted: Sun Jul 06, 2008 12:47 pm :
Has anyone tried it themselves yet? I'd be so sad if I never found out what was wrong.



cuteunit@Posted: Wed Jul 23, 2008 2:36 am :
No ideas on this one?



lowdragon@Posted: Wed Jul 23, 2008 7:39 am :
Didnt had the time to take a look into this - i thought about adding a own "playerList" similar to the "monsterList" so the script can differ. However this alone may not help with "process jumping" from player to player. :)



cuteunit@Posted: Sat Jul 26, 2008 8:15 am :
it bothers me greatly that it's so much easier to do things like this in an Unreal engine than it is in the Doom engine.



wal@Posted: Sat Jul 26, 2008 11:48 am :
If you're still having trouble with getOwner();, use this:
Code:
   entity weapon = getWeaponEntity();
   if ( weapon.getName() == "player1_weapon" ) {etc...



cuteunit@Posted: Tue Jul 29, 2008 2:06 pm :
I've run out of patience to keep trying at it... >_< though I'd still be quite happy if another got it to work