Save/Load Game and Weapons

Discuss programming in the QuakeC language.
Post Reply
SusanMDK
Posts: 601
Joined: Fri Aug 05, 2005 2:35 pm
Location: In The Sun

Save/Load Game and Weapons

Post by SusanMDK »

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: Select all

//==============================================================================
//  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: Select all

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: Select all

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!
Urre
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon
Contact:

Post by Urre »

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: Select all

.entity heldweapon;
Then you have a linked list of all the weapons in the entire game:

Code: Select all

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 ;)
I was once a Quake modder
SusanMDK
Posts: 601
Joined: Fri Aug 05, 2005 2:35 pm
Location: In The Sun

Post by SusanMDK »

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!
Post Reply