Inside3D!
     

Save/Load Game and Weapons

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> QuakeC Programming
View previous topic :: View next topic  
Author Message
jim



Joined: 05 Aug 2005
Posts: 400
Location: In The Sun

PostPosted: Sun Sep 30, 2007 10:43 pm    Post subject: Save/Load Game and Weapons Reply with quote

I solved my error, but you may take a look...

I have some trouble with save and load game and weapons using viewmodelforclient.

This is how it is when it's working: When I change a weapon, the old one goes down and when it's down and out of view, it is removed and then the new weapon is spawned to the view and it comes up from the bottom.

When it's not working, the weapon I had ready when I saved the game will be there twice when I load the game. This error doesn't happen with the original quake weapons, as they they don't use the weapon spawn and remove code. They use that self.weaponmodel ="v_some.mdl" stuff.

Every save will increase the amount of weapons been spawned errorneously.

This error doesn't only make two weapons appear to the screen, but it also makes their thinking happen too often. So they either have too fast fire rate or start the firing sequence again before the weapon actually fired anything...

Here's my code stuff:

This is in w_main.qc (formerly known as weapons.qc):
Code:

//==============================================================================
//  W_RemoveWeapon
// removes the weapon
//==============================================================================
void() W_RemoveWeapon =
{
   self.weaponmodel = "";
   if(self.hand_w)
      remove(self.hand_w);
   if(self.weapon_w)
      remove(self.weapon_w);
   self.weaponspawned = FALSE;
   dprint("weapons removed...\n");
};

//==============================================================================
//  W_TakeWeapon
// sets the take weapon up time when changing weapons
//==============================================================================
void() W_TakeWeapon =
{
   dprint("weapon take up...\n");

   // remove old weapons
   W_RemoveWeapon();

   if(self.newweapon == IT_HANDS)
      self.take_finished = time + 0.6;
   else if(self.newweapon == IT_EMPNP)
      self.take_finished = time + 1.2;
   // and same for every other weapon, which are still old quake weapons

   self.weaponstate = WS_TAKE;
   self.wpnaniframe = 0;
   self.weapon = self.newweapon;
   W_SetCurrentAmmo();
};

//==============================================================================
//  W_AwayWeapon
// sets the away weapon down time when changing weapons
//==============================================================================
void() W_AwayWeapon =
{
   dprint("weapon going away...\n");

   if(self.weapon == IT_HANDS)
      self.away_finished = time + 0.6;
   else if(self.weapon == IT_EMPNP)
      self.away_finished = time + 1.2;
   // and same for every other weapon, which are still old quake weapons

   self.weaponstate = WS_AWAY;
   self.wpnaniframe = 0;
};

//==============================================================================
//  W_WeaponAnimation
// animates the weapons
//==============================================================================
void() W_WeaponAnimation =
{
   if(self.weapon == IT_HANDS)
      W_Hands_Animation();
   else if(self.weapon == IT_EMPNP)
      W_EMPNP_Animation();
   else
      return;
};

//==============================================================================
//  W_WeaponFrame
// called every frame
//==============================================================================
void() W_WeaponFrame =
{
   // Weapon animations should be done always
   W_WeaponAnimation();
   
   // Impulse commands can be done, weapon won't change, if the player is firing..
   I_ImpulseCommands();

   // Doing an attack
   if(time < self.attack_finished)
      return;

   // Start putting the weapon down
   if(self.weapon != self.newweapon && (self.weaponstate == WS_READY_A || self.weaponstate == WS_READY_B))
      W_AwayWeapon();
   if(time < self.away_finished)
      return;

   // Start taking the weapon up
   if(self.weapon != self.newweapon && self.weaponstate == WS_AWAY)
      W_TakeWeapon();
   if(time < self.take_finished)
      return;

   // Attack
   if(self.button0)
   {
      self.weaponstate = WS_ATTACK_A;
      W_SuperDamageSound();      
      W_Attack();
      return;
   }

   // Alternate Attack
   if(self.button3)
   {
      self.weaponstate = WS_ATTACK_B;
      W_SuperDamageSound();
      W_AttackAlternate();
      return;
   }

   self.weaponstate = WS_READY_A;
};


And this is in my w_empnp.qc, which handles one of the weapons.. the IT_EMPNP, w_hands.qc is for IT_HANDS and currently it's almost a copy of this:
Code:

void() W_HandThink =
{
   if(!self.owner.frametics)
      self.owner.frametics = 0.1;
   self.nextthink = time + self.owner.frametics;   // how often to change frames, some actions change the frametics

   self.owner.wpnaniframe = self.owner.wpnaniframe + 1; // same kind of stuff as walkframe in player.qc
   self.frame = self.owner.weaponframe;
};

void() W_WeaponThink =
{
   // pretty much the same as W_HandThink, but has some stuff for changing the skin
};

void(entity hud_weapon) W_SpawnEMPNPHands =
{
   self.hand_w = spawn();
   self.hand_w.owner = hud_weapon;
   self.hand_w.movetype = MOVETYPE_NONE;
   self.hand_w.solid = SOLID_NOT;
   self.hand_w.classname = "cl_empnp_h";
   setmodel(self.hand_w, "model/cloaked_h/cl_empnp_h.dpm");
   self.hand_w.viewmodelforclient = hud_weapon;
   self.hand_w.skin = 0;
   self.hand_w.think = W_HandThink;
   self.hand_w.nextthink = time;
   dprint("empnp hands spawned...\n");
};

void(entity hud_weapon) W_SpawnEMPNP =
{
   // about the same as W_SpawnEMPNPHands, but spawns a self.weapon_w and use different model
};

void() W_EMPNP_Animation =
{
   // Spawn the weapons if they're not spawned
   if(self.weaponspawned == FALSE)
   {
      W_SpawnEMPNP(self);
      W_SpawnEMPNPHands(self);
      self.weaponspawned = TRUE;
   }
   // Taking the weapon
   if(time < self.take_finished)
   {
      empnp_take();
      return;
   }
   // Putting it away
   if(time < self.away_finished)
   {
      empnp_away();
      return;
   }
   // Attacking
   if(time < self.attack_finished)
   {
      if(self.weaponstate == WS_ATTACK_A)
         empnp_attack_a();
      else if(self.weaponstate == WS_ATTACK_B)
         empnp_attack_b();
      return;
   }
   // Ready to do anything
   if(self.weaponstate == WS_READY_A)
   {
      empnp_idle();
      return;
   }
};


So why aren't the self.hand_w and self.weapon_w removed after save and load? They aren't saved? How to save them then?

After eating some ice cream and doing something else for a moment, I found how to get rid of the error:

Code:

void() W_HandThink =
{
   // This prevents weapons being spawned again when loading a game
   // weaponspawned needs to set FALSE, otherwise player won't have any weapon
   // visible and can't do anything but change weapon...
   if(self.owner.hand_w != self)
   {
      self.owner.weaponspawned = FALSE;
      remove(self);
      return;
   }

   if(!self.owner.frametics)
      self.owner.frametics = 0.1;
   self.nextthink = time + self.owner.frametics;

   self.owner.wpnaniframe = self.owner.wpnaniframe + 1;
   self.frame = self.owner.weaponframe;
};

_________________
zbang!
Back to top
View user's profile Send private message Visit poster's website
Urre



Joined: 05 Nov 2004
Posts: 1073
Location: Sweden

PostPosted: Mon Oct 01, 2007 7:44 am    Post subject: Reply with quote

I haven't looked through all of your code, but I still have one major thing to point out in your code design: Don't remove and spawn new entities for held weapons. If you don't do this, you'll completely eliminate the entire possibility of the double weapons issue, since there's no weapon spawning happening, you can't accidentally spawn a weapon on top of another. What you want to do is this:

Have a field for the weapon in your hand, similar to how quake does it, but instead of a string, you make it an entity:

Code:
.entity heldweapon;


Then you have a linked list of all the weapons in the entire game:

Code:
entity weapon_list;
.entity w_next;

e = spawn();
e.mdl = "progs/v_plasmaweapon.mdl";
e.shootfunction = PlasmaShot;
etc...

e.w_next = weapon_list;
weapon_list = e;


Then all you need to do is scroll through the weapons list and check against the players inventory wether he owns this weapon or not, and then simply do the awesome trick of copying all the relevant info from the list to self.heldweapon, and play the raise animation. You just eliminated your problem, and made a really solid and smooth weapons handling system Wink
_________________
Look out for Twigboy
Back to top
View user's profile Send private message Visit poster's website
jim



Joined: 05 Aug 2005
Posts: 400
Location: In The Sun

PostPosted: Mon Oct 01, 2007 2:22 pm    Post subject: Reply with quote

This definitely sounds better than that spawning stuff, though now it seems to be working. But who knows if there's some more situations when it wants to spawn too much...

My weapons handling system is a bit not so solid and smooth. Using faster slowmo rate breaks it completely. The firing sequence is playing at somewhat random rate, though it's synchronized with both the hand and weapon entities.. I have a feeling it's not working well in netgames (I hope I'm wrong about that).
_________________
zbang!
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> QuakeC Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group