Announcement

Collapse
No announcement yet.

Trying to decipher some code

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Trying to decipher some code

    I'm trying to decipher some code here in order to modify it to do what I want. I'll refrain from saying what I want right now because I believe I can figure out how to do it if I can just get some help figuring out what everything means. I got a little bit of it figured out I think which I will note in the code.

    Code:
    ============
    W_WeaponFrame
    
    Called every frame so impulse events can be handled as well as possible
    ============
    */
    void() W_WeaponFrame = [COLOR="DarkOrange"]  // Not sure about below, but I believe it is a countdown mechanism which prevents the player from firing before the weapon has been reloaded.[/COLOR]
    {
    	
    	if (time < self.attack_finished)
    	{
    		if (self.weapon == IT_GRENADE_LAUNCHER && !self.button0 && self.ammo_rockets > 0)
    			self.attack_finished = time;
    		else if (self.weapon == IT_SHOTGUN && !self.button0 && self.ammo_shells > 0)
    			self.attack_finished = time;
    		return;
    	}
    		
    	ImpulseCommands ();
    	
    // check for attack   [COLOR="DarkOrange"]//  No idea about this one[/COLOR]
    	if (self.button0)
    	{
    		SuperDamageSound ();
    		W_Attack ();
    	}
    	else if (self.weapon == IT_GRENADE_LAUNCHER)
    	{ // autoload nade launcher
    		if (self.currentammo < 3 && self.currentammo < self.ammo_rockets) [COLOR="DarkOrange"]  // the player may have a maximum of 3 rockets loaded and if there are ever less than three, and the weapon is not being fired, then it loads one rocket[/COLOR]
    		{
    			if (self.currentammo < 1 && self.cnt != 1)[COLOR="DarkOrange"]  // check to see if ammo is 0 and self.cnt = 1?[/COLOR]
    			{
    				self.currentammo = 0;
    				self.cnt = 1; [COLOR="DarkOrange"]  // Not sure[/COLOR]
    				sound (self, CHAN_ITEM, "weapons/grenade_open.wav", 1, ATTN_NORM);
    			}
    			if ((time > self.attack_finished + 0.41 && self.currentammo > 0) || time > self.attack_finished + 0.56)  [COLOR="DarkOrange"]  //  this one is confusing me a bit though I know it must be related to the lines towards the top[/COLOR]
    			{
    				self.currentammo = self.currentammo + 1;
    				self.attack_finished = time;
    				sound (self, CHAN_ITEM, "weapons/grenade_load.wav", 1, ATTN_NORM);
    			}
    		}
    		else if (self.cnt == 1 && time > self.attack_finished + 0.41)
    		{
    			sound (self, CHAN_ITEM, "weapons/grenade_close.wav", 1, ATTN_NORM);
    			self.cnt = 0;
    		}
    	}
    	else if (self.weapon == IT_SHOTGUN)
    	{ // autoload shotgun
    		if (self.currentammo < 6 && self.currentammo < self.ammo_shells)
    		{
    			if (self.currentammo < 1 && self.cnt != 1)
    			{
    				self.currentammo = 0;
    				self.cnt = 1;
    			}
    			if ((time > self.attack_finished + 0.41 && self.currentammo > 0) || time > self.attack_finished + 0.56)
    			{
    				self.enemy = world; [COLOR="DarkOrange"]  //  I really want to know what this means[/COLOR]
    				self.currentammo = self.currentammo + 1; [COLOR="DarkOrange"] // Add 1 shell. not sure what dictates it though[/COLOR]
    				self.attack_finished = time; [COLOR="DarkOrange"] // Not sure[/COLOR]
    				sound (self, CHAN_ITEM, "weapons/sgload.wav", 1, ATTN_NORM);
    			}
    		}
    		else if (self.cnt == 1 && time > self.attack_finished + 0.41)
    		{
    			sound (self, CHAN_ITEM, "weapons/sgpump.wav", 1, ATTN_NORM);
    			self.cnt = 0;
    		}
    	}
    	
    };
    The code is used to auto-reload the shotgun and grenade launcher that have been modified to have semi-automatic fire. Each weapon has a magazine of a limited amount of ammo it can hold. Once the player fires off a single round and stops firing, the gun automatically begins to reload, but stops if the player fires again.

    Thanks to anyone who can provide some help.
    Last edited by Legend; 08-18-2014, 06:04 PM.

  • #2
    Im realy sorry that i cannot help you more due to the fact that i struggle to make any kind of code myself. And my autistic disorder makes dealing with very small numbers and bits of info realy difficult. But if you look at the source code for this mod you might find some functions to help improve your own.

    Quake 1 Mods - YouTube

    Although in all likelyhood youve probably seen this video before.
    We primarily speak english here...
    Is english a second language for you? If you are having trouble getting your point across please confront me on the forum or send me a PM. German is a second language for me and i will be able to provide the most help to those from deutschland.

    Comment


    • #3
      Originally posted by M_Luminoth View Post
      Im realy sorry that i cannot help you more due to the fact that i struggle to make any kind of code myself. And my autistic disorder makes dealing with very small numbers and bits of info realy difficult. But if you look at the source code for this mod you might find some functions to help improve your own.

      Quake 1 Mods - YouTube

      Although in all likelyhood youve probably seen this video before.
      Thanks anyway. but yes I have seen that vid. It's where the code I posted originally comes from. I'm just trying to modify it for a new weapon. Instead of reloading a single shell after each shot, I want it to only reload after all 12 rounds have been fired off and to take a substantial amount of time to reload.

      Comment


      • #4
        wow, if soup. Those numbers like 3 and 6 should be a constant. like

        if (self.currentAmmo < FULL_CLIP || etc...)

        and there is probably a cleaner way to write all of that. I could tell you what all that means but its too much of a pain on a phone keyboard. I don't want to pay my internet til my next phone bill is due. Sick of bills every week. Gonna get all the bills together in a pot and pay them all at once.
        Last edited by MadGypsy; 08-18-2014, 06:55 PM.
        http://www.nextgenquake.com

        Comment


        • #5
          Originally posted by MadGypsy View Post
          wow, if soup. Those numbers like 3 and 6 should be a constant. like

          if (self.currentAmmo < FULL_CLIP || etc...)

          and there is probably a cleaner way to write all of that. I could tell you what all that means but its too much of a pain on a phone keyboard. I don't want to pay my internet til my next phone bill is due. Sick of bills every week. Gonna get all the bills together in a pot and pay them all at once.
          No worries.

          6 and 3 are the magazine sizes. The shotgun has a magazine size of 6, the grenade launcher 3, and the one to be added will be 12.

          I would definitely like to hear your ideas on how to make it cleaner and some of the explanations when you have time at your computer instead of your phone.
          Last edited by Legend; 08-18-2014, 07:45 PM.

          Comment


          • #6
            Ok, I'll bring my laptop to work on Thursday and play with your code.
            http://www.nextgenquake.com

            Comment


            • #7
              I see one thing right now. I don't have a tab key on my phone so ill use dots

              float atk_fin = 0;
              if(!self.button0 && (self.weapon & (IT_GRENADE_LAUNCHER | IT_SHOTGUN)))
              {
              ....switch(self.weapon)
              ....{
              ........case IT_GRENADE_LAUNCHER:
              ............atk_fin = self.ammo_rockets;
              ............break;
              ........case IT_SHOTGUN:
              ............atk_fin = self.ammo_shells;
              ............break;
              ....}
              }

              if(atk_fin)
              ....self.attack_finished = time;
              Last edited by MadGypsy; 08-18-2014, 08:51 PM.
              http://www.nextgenquake.com

              Comment


              • #8
                Originally posted by MadGypsy View Post
                I see one thing right now. I don't have a tab key on my phone so ill use dots

                if(!self.button0)
                {
                ....switch(self.weapon)
                ....{
                ........case IT_GRENADE_LAUNCHER:
                ............//code
                ............break;
                ........case IT_SHOTGUN:
                ............//code
                ............break;
                ....}
                }
                Sorry, but I'm not sure what you mean by that. Are you just commenting on the syntax? The code itself is functioning. I didn't write it originally. I'm trying to understand it so I can modify it for use in a new weapon.

                Comment


                • #9
                  right and if you rewrote it in that style it would be even easier to figure out and modify.
                  Last edited by MadGypsy; 08-18-2014, 08:55 PM.
                  http://www.nextgenquake.com

                  Comment


                  • #10
                    No it wouldn't be easier switching to case. Would be slightly easier if the opening brace was on the same line... I prefer the inline numbers too. In fact, that is the most well written code I have ever seen! (except for the opening braces)

                    Are you really finding 2 else if conditions hard to follow?

                    If you were on a nix based system I would tell you to use grep to search all files for the strings you're interested in...
                    grep -r self.enemy *
                    grep -r world *
                    There's better ways to grok too...
                    Eventually you would understand.
                    Life is Grand!

                    Comment


                    • #11
                      Legend, you up to no good again? LOL! Ok... Perhaps we should first look at this code in it's original context to understand it's original function.


                      I bring you....... The original!


                      Code:
                      /*
                      ============
                      W_Attack
                      
                      An attack impulse can be triggered now
                      ============
                      */
                      void()	player_axe1;
                      void()	player_axeb1;
                      void()	player_axec1;
                      void()	player_axed1;
                      void()	player_shot1;
                      void()	player_nail1;
                      void()	player_light1;
                      void()	player_rocket1;
                      void()  player_rail1;
                      
                      void() W_Attack =
                      {
                      	local	float	r;
                      
                      	if (!W_CheckNoAmmo ())
                      		return;
                      
                      	makevectors	(self.v_angle);			// calculate forward angle for velocity
                      	self.show_hostile = time + 1;	// wake monsters up
                      
                      	if (self.weapon == IT_AXE)
                      	{
                      		sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
                      		r = random();
                      		if (r < 0.25)
                      			player_axe1 ();
                      		else if (r<0.5)
                      			player_axeb1 ();
                      		else if (r<0.75)
                      			player_axec1 ();
                      		else
                      			player_axed1 ();
                      		self.attack_finished = time + 0.5;
                      	}
                      	else if (self.weapon == IT_SHOTGUN)
                      	{
                      		player_shot1 ();
                      		W_FireShotgun ();
                      		self.attack_finished = time + 0.5;
                      	}
                      	else if (self.weapon == IT_SUPER_SHOTGUN)
                      	{
                      	player_shot1 ();
                      		W_FireSuperShotgun ();
                      		self.attack_finished = time + 0.7;
                      	}
                      	else if (self.weapon == IT_NAILGUN)
                      	{
                      		player_nail1 ();
                      	}
                      	else if (self.weapon == IT_SUPER_NAILGUN)
                      	{
                      		player_nail1 ();
                      	}
                      	else if (self.weapon == IT_GRENADE_LAUNCHER)
                      	{
                      		player_rocket1();
                      		W_FireGrenade();
                      		self.attack_finished = time + 0.6;
                      	}
                      	else if (self.weapon == IT_ROCKET_LAUNCHER)
                      	{
                      		player_rocket1();
                      		W_FireRocket();
                      		self.attack_finished = time + 0.8;
                      	}
                      	else if (self.weapon == IT_LIGHTNING)
                      	{
                      		player_light1();
                      		self.attack_finished = time + 0.1;
                      		sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
                      
                      };
                      /*
                      ============
                      ImpulseCommands
                      
                      ============
                      */
                      void() ImpulseCommands =
                      {
                      	if (self.impulse >= 1 && self.impulse <= 8)
                      		W_ChangeWeapon ();
                      
                      	if (self.impulse == 9)
                      		CheatCommand ();
                      	if (self.impulse == 10)
                      		CycleWeaponCommand ();
                      	if (self.impulse == 11)
                      		ServerflagsCommand ();
                      	if (self.impulse == 12)
                      		CycleWeaponReverseCommand ();
                      
                      	if (self.impulse == 255)
                      		QuadCheat ();
                      		
                      	self.impulse = 0;
                      };
                      
                      /*
                      ============
                      W_WeaponFrame
                      
                      Called every frame so impulse events can be handled as well as possible
                      ============
                      */
                      void() W_WeaponFrame =
                      {
                      	if (time < self.attack_finished)
                      		return;
                      
                      	ImpulseCommands ();
                      	
                      // check for attack
                      	if (self.button0)
                      	{
                      		SuperDamageSound ();
                      		W_Attack ();
                      	}
                      };
                      
                      /*
                      ========
                      SuperDamageSound
                      
                      Plays sound if needed
                      ========
                      */
                      void() SuperDamageSound =
                      {
                      	if (self.super_damage_finished > time)
                      	{
                      		if (self.super_sound < time)
                      		{
                      			self.super_sound = time + 1;
                      			sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
                      		}
                      	}
                      	return;
                      };

                      This is all the relevant code without the fluff. So lets start with the W_WeaponFrame

                      Code:
                      /*
                      ============
                      W_WeaponFrame
                      
                      [COLOR="Yellow"]Called every frame so impulse events can be handled as well as possible[/COLOR]
                      [COLOR="Red"]^^^^This says it all![/COLOR]
                      ============
                      */
                      void() W_WeaponFrame =
                      {
                      	[COLOR="DarkOrange"]if (time < self.attack_finished) 
                      		return;[/COLOR] [COLOR="Red"]//If time hasn't finished on current weapon attack animation this this stops the function from going any further.
                      [/COLOR]
                      	ImpulseCommands (); [COLOR="Red"]//This allows for additional Impulse commands to be used like switching weapons[/COLOR]
                      	
                      // check for attack 
                      	if (self.button0) [COLOR="Red"] //This one says if you are pressing the fire button down then, next [/COLOR]
                      	{
                      		SuperDamageSound (); [COLOR="Red"]//If you happen to have Quad make this sound when you fire[/COLOR]
                      		W_Attack ();  [COLOR="Red"]//Start function to define weapon parameters while firing (weapon start animation,fire function to use, time between fire function calls [/COLOR]
                      	}
                      };

                      W_WeaponFrame gets used in client.qc so check it out for more details. tl;dr version is the client.qc needs this function to check for certain events happen on the client postthink.

                      Now Impulse Commands we will skip because I think those are self explanatory. Now W_Attack.


                      Code:
                      ============
                      W_Attack
                      
                      An attack impulse can be triggered now [COLOR="Red"]//Self explanatory but basically when you press your shoot button on the mouse or keyboard it will actually do something :) .[/COLOR] 
                      ============
                      */ [COLOR="red"]//All The Animation Stuff you'll find in player.qc that have to be defined here because of order of compile[/COLOR]
                      void()	player_axe1;
                      void()	player_axeb1;
                      void()	player_axec1;
                      void()	player_axed1;
                      void()	player_shot1;
                      void()	player_nail1;
                      void()	player_light1;
                      void()	player_rocket1;
                      void()  player_rail1;
                      
                      void() W_Attack =
                      {
                      	local	float	r;
                      
                      	if (!W_CheckNoAmmo ()) [COLOR="red"]//If the ammo hasn't been checked yet don't run this function until you do. [/COLOR]
                      		return;
                      
                      	makevectors	(self.v_angle);			// calculate forward angle for velocity
                      	self.show_hostile = time + 1;	// wake monsters up
                      
                      	if (self.weapon == IT_AXE)
                      	{
                      		sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
                      		r = random();
                      		if (r < 0.25)
                      			player_axe1 ();
                      		else if (r<0.5)
                      			player_axeb1 ();
                      		else if (r<0.75)
                      			player_axec1 ();
                      		else
                      			player_axed1 ();
                      		self.attack_finished = time + 0.5;
                      	}
                      	else if (self.weapon == IT_SHOTGUN)  [COLOR="red"]//These are defining the first animations to use, the function to use when firing, and the time alotted between one fire animation and the next allowed. [/COLOR]
                      	{
                      		player_shot1 ();
                      		W_FireShotgun ();
                      		self.attack_finished = time + 0.5; [COLOR="red"]//The lower this number the faster you can fire (RAPID FIRE!)[/COLOR]
                      	}
                      	else if (self.weapon == IT_SUPER_SHOTGUN)
                      	{
                      	player_shot1 ();
                      		W_FireSuperShotgun ();
                      		self.attack_finished = time + 0.7;
                      	}
                      	else if (self.weapon == IT_NAILGUN)
                      	{
                      		player_nail1 ();
                      	}
                      	else if (self.weapon == IT_SUPER_NAILGUN)
                      	{
                      		player_nail1 ();
                      	}
                      	else if (self.weapon == IT_GRENADE_LAUNCHER)
                      	{
                      		player_rocket1();
                      		W_FireGrenade();
                      		self.attack_finished = time + 0.6;
                      	}
                      	else if (self.weapon == IT_ROCKET_LAUNCHER)
                      	{
                      		player_rocket1();
                      		W_FireRocket();
                      		self.attack_finished = time + 0.8;
                      	}
                      	else if (self.weapon == IT_LIGHTNING)
                      	{
                      		player_light1();
                      		self.attack_finished = time + 0.1;
                      		sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
                      
                      };

                      In conclusion W_WeaponFrame allows all frames to run in a weapon animation and then waits for the alotted time has expired between each weapon function fire before allowing the next set of animations and fire sequences to occur. Now you should know the basics of these functions.

                      Now to your specific needs.

                      Ok this one I am just going to write out in plain English so you get the gist of what is going on. But first a word on self.cnt. This is defined firstly in defs.qc as .float cnt, why .float? it's a flag. It uses either 1 or 0. 1 meaning it's active and cannot be used and 0 meaning it's inactive and can be used. That should help explain more what is going on. You can see some uses of this flag more in subs.qc for a few more examples.

                      lets break this code down:

                      Code:
                      if (time < self.attack_finished)
                      	{
                      		if (self.weapon == IT_GRENADE_LAUNCHER && !self.button0 && self.ammo_rockets > 0)
                      			self.attack_finished = time;
                      		else if (self.weapon == IT_SHOTGUN && !self.button0 && self.ammo_shells > 0)
                      			self.attack_finished = time;
                      		return;
                      
                      [COLOR="red"]Basically it looks for the weapon in question first, and if you do not have the fire button pressed, and you are not out of ammo/clip is not empty, then the function will end because you don't want to reload yet. You already have something else in store for it. ;)  This goes for Grenade Launcher and the basic Shotty. [/COLOR]
                      
                      else if (self.weapon == IT_GRENADE_LAUNCHER)
                      	{ // autoload nade launcher
                      		if (self.currentammo < 3 && self.currentammo < self.ammo_rockets)  
                      
                      [COLOR="red"]If the weapon is currently a Grenade Launcher and if your current ammo/clip is less than 3 go ahead and check the next instructions.[/COLOR] 
                      
                      if (self.currentammo < 1 && self.cnt != 1)  
                      
                      [COLOR="Red"]If your clip is empty and you are currently not busy then move to the next step.[/COLOR]
                      
                      self.currentammo = 0;
                      self.cnt = 1; 
                      sound (self, CHAN_ITEM, "weapons/grenade_open.wav", 1, ATTN_NORM);
                      
                      [COLOR="red"]Set current ammo to 0, Probably already so, then set yourself to busy, now open the grenade for reload (play sound).[/COLOR] 
                      
                      if ((time > self.attack_finished + 0.41 && self.currentammo > 0) || time > self.attack_finished + 0.56)
                      [COLOR="red"]if your weapon fire routine is partially finished and your clip still has ammo or if your fire routine is competely finished move to these instructions.[/COLOR]
                      
                      self.currentammo = self.currentammo + 1;
                      self.attack_finished = time;sound (self, CHAN_ITEM, "weapons/grenade_load.wav", 1, ATTN_NORM);
                      
                      [COLOR="red"]Go ahead and load a grenade and listen to that sweet sound while you load it! :)[/COLOR]
                      
                      else if (self.cnt == 1 && time > self.attack_finished + 0.41)
                      		{
                      			sound (self, CHAN_ITEM, "weapons/grenade_close.wav", 1, ATTN_NORM);
                      			self.cnt = 0;
                      
                      [COLOR="red"]Otherwise, If you are still busy and your routine is complete close the grenade launcher (play sound) and set yourself to not busy. 
                      [/COLOR]
                      Basically this code takes presistent if the grenade launcher meets those parameters first instead of simply going to W_Attack.
                      Most of the code for the shotgun is the same but you did ask about this section that I will comment on:

                      Code:
                      self.enemy = world;
                      Ok this is just setting it to no enemy. Why? it's related to this code:

                      Code:
                      else if (self.weapon == IT_SHOTGUN)
                      	{
                      		if (self.flags & FL_CLIENT) {
                      			if (self.enemy != multi_ent)
                      			{
                      				self.count = 0;
                      				self.enemy = multi_ent;
                      			} else if (multi_damage > 24) {
                      				self.count = self.count + 1;
                      				sound (multi_ent, CHAN_ITEM, "weapons/crit_hit.wav", 1, ATTN_NORM);
                      			} else {
                      				self.count = 0;
                      				self.enemy = multi_ent;
                      This code sets an enemy for the weapon for the multi damage scenario. This is fine, but in order to do the reload event this enemy has to be cleared first. So changing it to world is basically saying you now have no enemy and can proceed to a new set of instructions. More or less. You mostly see this is AI Bot or Monster code.

                      I think I covered everything. If not, let me know. Hope you have a a better understanding of the syntax now.

                      Cheers!
                      Last edited by PrimalLove; 08-19-2014, 05:12 AM.

                      Comment


                      • #12
                        I'm glad somebody finally decided to help, and he (she?) did a pretty good job, but I'd like to explain some things, too.

                        Code:
                        if (time < self.attack_finished)
                        {
                        	if (self.weapon == IT_GRENADE_LAUNCHER && !self.button0 && self.ammo_rockets > 0)
                        		self.attack_finished = time;
                        	else if (self.weapon == IT_SHOTGUN && !self.button0 && self.ammo_shells > 0)
                        		self.attack_finished = time;
                        	return;
                        }
                        One thing that happens a lot in quake code is setting things to happen in the future. This is sometimes done with a .think function and .nextthink time value (seconds from server launch), as you might have noticed. This is done by constantly checking every entity's .nextthink time against the current time (and then running the .think function). Similarly, this particular block of code is checking .attack_finished, which will sometimes contain a future number in seconds. Thus, we are checking to see if the attack has finished animating (or at least, the defined delay between shots has passed). The interesting thing here is setting self.attack_finished to the current time, which is like saying the player can now attack, without delay. It seems like you could fire three times (or 6 with SSG) as quick as you want, as long as you let go of the attack button between shots.


                        Code:
                        if (self.button0)
                        {
                        	SuperDamageSound ();
                        	W_Attack ();
                        }
                        else if (self.weapon == IT_GRENADE_LAUNCHER)
                        {
                        	if (self.currentammo < 3 && self.currentammo < self.ammo_rockets)
                        	{ ... }
                        }
                        else if (self.weapon == IT_SHOTGUN)
                        { ... }
                        self.button0 is either zero or one, depending if the "self" player is pressing the attack button. Self.currentammo is the number you see in the bottom right of your HUD. Typically, this is just simply set to your current weapon's ammo type, but for this mod, it shows how much ammo is loaded.

                        Further down is:
                        Code:
                        	if (self.currentammo < 1 && self.cnt != 1) 
                        	{
                        		self.currentammo = 0;
                        		self.cnt = 1;   // Not sure
                        		sound (self, CHAN_ITEM, "weapons/grenade_open.wav", 1, ATTN_NORM);
                        	}
                        	if ((time > self.attack_finished + 0.41 && self.currentammo > 0) || time > self.attack_finished + 0.56) 
                        	{
                        		self.currentammo = self.currentammo + 1;
                        		self.attack_finished = time;
                        		sound (self, CHAN_ITEM, "weapons/grenade_load.wav", 1, ATTN_NORM);
                        	}
                        }
                        else if (self.cnt == 1 && time > self.attack_finished + 0.41)
                        {
                        	sound (self, CHAN_ITEM, "weapons/grenade_close.wav", 1, ATTN_NORM);
                        	self.cnt = 0;
                        }
                        If you notice, you can see .cnt is 0 or 1, depending on the player's situation. Basically, it causes the grenade_close sound to play ONCE after reloading is complete. (self.cnt being 1 means the sound is ok to play, but remember that the block with the sound() function can only be accessed if none of the other ifs are true.) ... After taking a peek, the line with 0.41 and 0.56 tells me that a player will take an extra 0.15 seconds to reload an empty weapon; so you better make that last shot count, if you take it. Additionally, once you're reloaded, you can now attack immediately (due to "self.attack_finished = time;").

                        Code:
                        self.enemy = world;
                        Normally, a player's .enemy isn't used. But consider a monster. A monster's enemy will usually be the last thing that hit it. When a monster does not have an enemy, its enemy is "world". world is technically a thing, but you're not typically allowed to use it. Think of world as "zero". But, keep in mind you have to check if an entity is world, if it can ever be set to world. That's why you can sometimes see checks if an entity is world.

                        Primal touched on its purpose in this mod, for a player to have an .enemy set. He (She?) found where it was used (where it plays "crit_hit.wav"), and I can see that the mod counts how much of a shotgun blast hits another player in order to play this extra sound. I would expect "self.enemy = world;" to be set after each shot, but it seems the way they wrote it is to allow multiple shots to combine in order to count towards the requirement to play the sound. So, it sounds like this code prevents shots AFTER a reload to count towards this total. BUT then you have to understand what multi_ent is to really make sure. I won't get into this detail, but it's a mechanic of shotgun blasts combining into one hit worth of damage. I don't actually know where the code Primal posted is found, nor do I know if they edited this shotgun blast mechanic to suit their needs, so I can't say more about it.

                        One thing to note, is that they use .currentammo a bit differently. So, if you drop this code into vanilla quake, you will have to find other code that uses .currentammo and change it to make sure partially-loaded weapons don't lose their "loadedness".

                        Comment


                        • #13
                          Thanks Zop. That was very informative.

                          I do have the rest of the code as well. I have been going over it and modifying it for some time now. I understand a decent bit so far. It was mostly the snippet that I posted that had me stumped the most. I understood what it controlled as a whole but didn't really understand how it worked exactly and which bits did what.

                          Thanks again.

                          Comment

                          Working...
                          X