Announcement

Collapse
No announcement yet.

Very Simple QC & ent Mod

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

  • Very Simple QC & ent Mod

    This is how to treat a radiant point entity like an effects brush. This is also gonna be considered a STONER level/friendly tutorial. Of course I am not trying to imply JD in particular .

    Make a new qc file, name it whatever you want and add it at the very bottom of your progs.src. Imma call mine spawns.qc. The reason why I am putting this microscopic amount of code in it's own QC, is because maybe I will teach you more stuff later of the "spawn" type and you can just keep adding to it.

    spawns.qc
    Code:
    .string effectname;
    
    void() seven_think =
    {	self.nextthink = time + 0.00065;
    	pointparticles(particleeffectsnum(self.effectname), self.origin, '0 0 0', 1);
    };
    
    void() spawn_effect =
    {	if(!self.effectname)
    	{	objerror("spawn_effect: you didn't set the effectname field.\n");
    		return;
    	}
    
    	self.think = seven_think;
    	self.nextthink = time + 0.1;
    };
    This is simple and it's also QC so we will be working from the bottom up. You will be calling spawn_effect from the map. If there is no effectname set it throws an error and exits the function, otherwise it thinks about seven after a brief pause.

    seven_think just keeps running pointparticles over and over and over. In pointparticles is the effect name from your effectinfo.txt and some other values that you can learn about by opening dpextensions and reading the comments.

    Arbitrary explanation: the "self" in spawn_effect is the same "self" as seven_think. I know it would seem like they are different but they are not. spawn_effect CALLED seven_think from within itself. So seven_think is like an expansion of "self" as opposed to a separation of. We already defined that think is seven_think and in seven_think it keeps saying to think again (nextthink). Seven_think runs forever once its called (multiplied by the amount of effects used) and we never programmed in a way to shut it off.

    Finally, we make the possibility of an .effectname field possible.


    NOTE: you don't have to have that new var (.effectname). You could erase it's declaration and then change everywhere it is used (entities.ent too) to self.model

    I like things to make sense. I like to be able to look at something and immediately know what it is. .model does not accurately express that the name of an effect should be its value, so I make new vars.


    Make sure you have dpextensions and this script included in your progs.src and recompile your qc.

    ------


    Now let's build the radiant ent definition. Open up your entities.ent and add the following lines right before </classes> (the very bottom)

    Code:
    	<point name="spawn_effect" color="0 .5 .8" box="-4 -4 -4 4 4 4">
    		<string key="effectname" name="effectname"> the name of your effect from effectinfo.txt</string>
    	</point>
    ---

    If you do not already have some effects, paste this in an empty document and save it as "effectinfo.txt" in your root game folder. (ie ID1 .. not /maps - that only works for mapname_effectinfo.txt)

    Quake/id1/effectinfo.txt
    Code:
    effect simplesmoke
    countabsolute .1
    type smoke
    color 0x222233 0xeeeeff
    tex 0 7
    size 1 6
    alpha 20 7 2
    sizeincrease -5
    originoffset 0 10 0
    originjitter 128 128 0
    velocityjitter 7 7 3
    velocitymultiplier 0.1
    gravity -0.0005
    bounce 1
    You will also need a particle font and it will need to be placed in id1/particles. If the entire top row (0 thru 7) of your particle font does not look like smokey stuff, you will need to change {tex 0 7} to whatever numbers apply for your particle font.

    ---

    Last but not least - open up radiant, make a room or choose a room (whatever applies) in your map and right click. Select spawn_effect from the drop down list. Open the entity inspector (with spawn_effect active). Next to effectname, write "simplesmoke" (or whatever effect name you desire and possess) . Save/Compile/Run and enjoy.

    fun fact?: I typed all of this out. I didn't even copy/paste my own tutorial, that's a fact. I did it that way, cause I wanted to see if I was right. I checked my script against my original before posting. I missed a semi-colon after a function, that isn't even a warning (i think lol). Anyway, you can't ever stop typing if you want to be good, JD. I made this tut cause you mentioned it in sevens thread.
    Last edited by MadGypsy; 05-26-2013, 08:59 PM.
    http://www.nextgenquake.com

  • #2
    thanks man ill work with this!

    Comment


    • #3
      You are welcome. I'll tell you a little bonus secret. You could open items.qc, go to to PlaceItem and make it like below.

      Code:
      void() PlaceItem =
      {
      	self.mdl = self.model;		// so it can be restored on respawn
      	self.flags = FL_ITEM;		// make extra wide
      	self.solid = SOLID_TRIGGER;
      	self.movetype = MOVETYPE_TOSS;	
      	self.velocity = '0 0 0';
      	self.origin_z = self.origin_z + 6;
      	if (!droptofloor())
      	{
      		dprint ("Bonus item fell out of level at ");
      		dprint (vtos(self.origin));
      		dprint ("\n");
      		remove(self);
      		return;
      	}
      	[COLOR="Orange"]spawn_effect();[/COLOR]
      };
      If you do this, you are gonna have to put spawns.qc higher up the chain in progs.src. Right above items.qc should work fine.

      The spawn_effect function will now need to be:

      Code:
      void() spawn_effect =
      {	if(!self.effectname)
      	{	[COLOR="Orange"]if(self.classname == "spawn_effect")
      		{[/COLOR]	objerror("spawn_effect: you didn't set the effectname field.\n");
      			return;
      		[COLOR="Orange"]}
      	[/color]}[COLOR="Orange"] else {[/COLOR]
      		self.think = seven_think;
      		self.nextthink = time + 0.1;
      	[COLOR="Orange"]}[/COLOR]
      };
      The extra condition will stop items that do not have an effectname from throwing object errors. Do you want to know why? Imma tell you anyway. When you put spawn_effect in a map directly it's classname is automatically "spawn_effect", but if you call spawn_effect() from within another function/entity (same diff) the classname will be that of the calling entity and self will actually BE the calling entity. So, you see? The only time it will throw that error, is if spawn_effect is a standalone entity in the map that does not have an effectname set (its only purpose... to have an effectname). But as an "add-on" entity we don't want that throwing errors. We make it a "silent" option. The else is just saying THERE IS an effectname set so, regardless of what set it, start thinking.

      Now what you can do is, open up your map and on any item you can add:

      key: effectname
      value: {NAME OF EFFECT}

      When you save/compile/run, that item will be emitting the effect.

      You could directly add this into your ent, but it would be time consuming. You would have to add one line to every single item.

      Code:
      		<string key="effectname" name="effectname"> the name of your effect from effectinfo.txt</string>
      Last edited by MadGypsy; 05-26-2013, 08:56 PM.
      http://www.nextgenquake.com

      Comment


      • #4
        NOTE: I said that self will BE the calling entity. This is completely or not-at-all true. self (unless redefined) will always be the most parentest object. So if:

        starting with item_armor1 calls StartItem calls PlaceItem calls spawn_effect calls seven_think

        item_armor1 is self in every one of those. Which means self.classname is "item_armor1" as well. Unless of course somewhere in the chain of code the classname was explicitly redefined. An example of this would be func_door. The classname gets changed to "door". However, that does not happen in this case.

        You only need to ever ask yourself, where did this all start? That is self... unless you find somewhere in the chain where self is being redefined. (which usually that is temporary - I call it the ol switcheroo (LOL))


        The Ol' Switcheroo
        Code:
        stemp = self;					//store current self
        self = something_else;				//redirect to some other entity
        self.this = ( self.that & self.the_other );	//do stuff with new self
        self = stemp;					//switch back
        Last edited by MadGypsy; 05-26-2013, 09:14 PM.
        http://www.nextgenquake.com

        Comment


        • #5
          i used a function with brushes to spawn effects in an area (not a point)

          .float efectusando;
          .string particleffect;
          void () particula_think=
          {
          if (self.owner.efectusando == 1)
          pointparticles(particleeffectnum(self.owner.partic leffect), self.origin, '0 0 0', 1);

          self.nextthink = time + self.owner.wait;
          //self.nextthink = time;
          self.think = particula_think;
          };


          void( entity f) spawn_efectos =
          {

          local entity drop;
          drop = spawn ();
          drop.owner = f;
          drop.skin = random () * 2;
          drop.origin_x = self.absmin_x + (random() * f.size_x);
          drop.origin_y = self.absmin_y + (random() * f.size_y);
          drop.origin_z = self.absmin_z + (random() * f.size_z);
          setmodel (drop, "progs/nada.spr");
          drop.classname = "efectos_spuff";
          drop.think = particula_think;
          drop.nextthink = time;
          };
          void() efectos_think =
          {
          local float tamano_efector;


          tamano_efector = ((self.size_x * self.size_y * self.size_z) / 2000) * self.cnt;
          while (tamano_efector > -1)
          {
          spawn_efectos(self);
          tamano_efector = tamano_efector - 1;
          }

          //self.nextthink = time + (random() * self.wait);
          //self.think = efectos_think;
          };
          void () use_efectos
          {

          if (self.efectusando == 2)
          self.efectusando = 1;
          else
          self.efectusando = 2;

          };
          void () func_efectos =
          {
          setmodel (self, self.model);
          self.movetype = MOVETYPE_PUSH;
          setmodel (self, self.model);
          if (!self.efectusando)
          self.efectusando = 1;
          self.think = efectos_think;
          self.nextthink = time;
          if (!self.count)
          self.count = (self.absmax_x - self.absmin_x)*(self.absmax_y - self.absmin_y)/ 4096 ;
          if (!self.wait)
          self.wait = 0.01;
          self.use = use_efectos;
          if (!self.cnt)
          self.cnt = 0.5;
          if (!self.speed)
          self.speed = 200;
          if (!self.particleffect)
          self.particleffect = "simplesmoke";
          };/////////////
          use the values particleusando (for activate the trigger), particleffect (for the name of effects) speed and cnt for the mount of particles in the brush and wait for the respawn of particles
          the invasion has begun! hide your children, grab the guns, and pack sandwiches.

          syluxman2803

          Comment


          • #6
            lol, that took the "simple" out of my title.

            Great work, though!
            http://www.nextgenquake.com

            Comment


            • #7
              Originally posted by MadGypsy View Post
              lol, that took the "simple" out of my title.

              Great work, though!
              hahahaha sure my little function is simple if you do not believe me see the wapzone code!!!
              the invasion has begun! hide your children, grab the guns, and pack sandwiches.

              syluxman2803

              Comment


              • #8
                yeah, when I first looked at t it looked long and crazy, confusing even, because you use some wierd box that isn't even a code or quote box and it strips all the formatting. When I rewrote it in english and applied the proper formatting, the script was revealed as being very simple.

                But on top of no formatting and it being written in spanish (sorta) you didn't explain any of it, so the audience I am trying to reach probably still thinks your code is not simple. It's definitely not simple to read.

                You should care more about your code posts and post it with the proper formatting. You also have errors in your code.

                1) you have a "hanging" space
                Code:
                pointparticles(particleeffectnum(self.owner.partic leffect), self.origin, '0 0 0', 1);
                2) you may be the only person here with a (progs/nada.spr)
                Last edited by MadGypsy; 05-27-2013, 08:11 AM.
                http://www.nextgenquake.com

                Comment


                • #9
                  Originally posted by MadGypsy View Post
                  yeah, when I first looked at t it looked long and crazy, confusing even, because you use some wierd box that isn't even a code or quote box and it strips all the formatting. When I rewrote it in english and applied the proper formatting, the script was revealed as being very simple.

                  But on top of no formatting and it being written in spanish (sorta) you didn't explain any of it, so the audience I am trying to reach probably still thinks your code is not simple. It's definitely not simple to read.

                  You should care more about your code posts and post it with the proper formatting. You also have errors in your code.

                  1) you have a "hanging" space
                  Code:
                  pointparticles(particleeffectnum(self.owner.partic leffect), self.origin, '0 0 0', 1);
                  2) you may be the only person here with a (progs/nada.spr)
                  hahaha nada.spr es just an empty (or null sprite) sorry for the issues, aniway, i can not write code totally in english or add comments, you know my english is very bad . This code is just an example to spawn entities in a brush that will spawn particles
                  the invasion has begun! hide your children, grab the guns, and pack sandwiches.

                  syluxman2803

                  Comment


                  • #10
                    I reworked Nahuels code, fixed all the errors, removed useless vars and turned it into English.

                    Code:
                    float EFF_RISE 		= 1;
                    float EFF_FALL 		= 2;
                    float EFF_VOLUME 	= 4;
                    
                    .string effectname;
                    
                    void() effect_think =
                    {	self.nextthink = time + 0.00065;
                    	pointparticles(particleeffectnum(self.effectname), self.origin, '0 0 0', 1); 
                    };
                    
                    void() particle_think =
                    {	if(self.owner.effectname)
                    		pointparticles(particleeffectnum(self.owner.effectname),self.origin,'0 0 0',1);
                    		
                    	self.nextthink = time + self.wait;
                    	self.think = particle_think;
                    };
                    
                    void() spawn_point_effect =
                    {	if( check_string(self.effectname) )
                    	{	self.think = effect_think;
                    		self.nextthink = time + 0.1; 
                    	} else {
                    		if(self.classname == "spawn_point_effect")
                    		{	dprint("you did not set the effectname field");
                    			return;
                    		}
                    	}
                    };
                    
                    void(entity area) spawn_effect_particle =
                    {	local entity drop;
                    	drop = spawn();
                    	drop.owner = area;
                    	drop.skin = random()*2;
                    	drop.origin_x = self.absmin_x + ( random() * area.size_x );
                    	drop.origin_y = self.absmin_y + ( random() * area.size_y );
                    	
                    	if(self.spawnflags & EFF_RISE) drop.origin_z = self.absmin_z;
                    	else if(self.spawnflags & EFF_FALL) drop.origin_z = self.absmax_z;
                    	else
                    	{	drop.origin_z = self.absmin_z + ( random() * area.size_z );
                    		self.spawnflags = self.spawnflags | EFF_VOLUME;
                    	}
                    	
                    	setmodel(drop, "");
                    	
                    	drop.think = particle_think;
                    	drop.nextthink = time;
                    };
                    
                    void() effect_think2 =
                    {	while (self.cnt > -1)
                    	{	spawn_effect_particle(self);
                    		self.cnt-=1;
                    	}
                    };
                    
                    void() spawn_area_effect =
                    {	self.spawnflags = self.spawnflags | INVISIBLE;
                    
                    	if(!self.wait)self.wait = 5;
                    	if(!self.cnt)self.cnt = 100;
                    
                    	if( check_string(self.effectname) )
                    	{	self.think = effect_think2;
                    		self.nextthink = time + 0.1; 
                    	} else {
                    		if(self.classname == "spawn_area_effect")
                    		{	dprint("you did not set the effectname field");
                    			return;
                    		}
                    	}
                    	self.angles = '0 0 0';
                    	self.movetype = MOVETYPE_NONE;
                    	self.solid = SOLID_NOT;
                    	
                    	setmodel(self,self.model);
                    	setorigin(self,self.origin);
                    	setsize(self,self.mins,self.maxs);
                    
                    	self.model = "";
                    };
                    I also changed a few things:

                    1) self.cnt is the exact amount of particles points you want to use. If you want 1000 spots spitting out particles in your volume, then self.cnt = 1000 will make that happen.

                    2) Nahuels code didn't consider that particles may need to be spawned level with the top (rain) or bottom (smoke) of the volume. Now you can set either EFF_FALL or EFF_RISE to get the appropriate spawn_z. Omitting both will default to EFF_VOLUME

                    3) progs/nada.spr was completely unnecessary and has been replaced with "nothing"

                    here is the radiant .ent definition as well, add at the end before </classes>
                    Code:
                    <group name="spawn_area_effect" color=".2 .2 .2">
                    	<flag key="EFF_RISE" name="EFF_RISE" bit="0"/>
                    	<flag key="EFF_FALL" name="EFF_FALL" bit="1"/>
                    	<string key="effectname" name="effectname" />
                    	<real key="wait" name="wait" />
                    	<real key="cnt" name="cnt" />
                    </group>
                    some things to note:

                    1: in effectinfo.txt "originjitter" represents the area in every direction from center to spawn the effect. Considering that each particle point is emitting the effect, you may want to keep that number really low, like '1 1 1'

                    2: just because your self.cnt = 1000 does not mean you are spawning 1000 particles. What it does mean, is you are spawning 1000 emitters. Each emitter could be spawning 7000,000 particles, it all depends on your effects code.
                    Last edited by MadGypsy; 06-09-2013, 06:13 AM.
                    http://www.nextgenquake.com

                    Comment


                    • #11
                      WOOPS: I double, triple, quintuple check everything before I consider something "entire" but sometimes I still miss things. The above post had 1 oversight and one mistake. It has all been fixed.

                      The oversight: I didn't include any of the spawnflags in the radiant definition (lol)
                      the mistake: I was multiplying .absmax where it should have been .absmin in one spot

                      sorry for any headaches that may have caused.

                      note: you don't need the EFF_VOLUME flag in the radiant ent cause it is the default for this brush. Just don't set RISE or FALL and it will automatically be VOLUME.
                      Last edited by MadGypsy; 06-09-2013, 06:10 AM.
                      http://www.nextgenquake.com

                      Comment


                      • #12
                        Originally posted by MadGypsy View Post
                        WOOPS: I double, triple, quintuple check everything before I consider something "entire" but sometimes I still miss things. The above post had 1 oversight and one mistake. It has all been fixed.

                        The oversight: I didn't include any of the spawnflags in the radiant definition (lol)
                        the mistake: I was multiplying .absmax where it should have been .absmin in one spot

                        sorry for any headaches that may have caused.

                        note: you don't need the EFF_VOLUME flag in the radiant ent cause it is the default for this brush. Just don't set RISE or FALL and it will automatically be VOLUME.
                        actually i just use beziers (actually planes ) for the original function but beziers are a feature in q3bsp!! not in q1bsp
                        the invasion has begun! hide your children, grab the guns, and pack sandwiches.

                        syluxman2803

                        Comment

                        Working...
                        X