Announcement

Collapse
No announcement yet.

QuakeC Developer Tools?

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

  • #16
    Originally posted by MadGypsy View Post
    Here was the "class" that forced errors and recorded warnings. Understand that these custom messages are intended to make sure that MY code is being used the way I intended and to spit out warnings that can help you track down missing properties in YOUR MAP.

    In other words. A whole lot of this is stuff that a stack trace isn't going to report.

    Code:
    //	Gypsy:Gnome - Exceptions Manager | build 20130513-14:39cn
    float ERR_GNOMENAME 			= 1;
    float ERR_MODELPATH 			= 2;
    float ERR_SOUNDPATH 			= 3;
    float ERR_EFFECTNAME			= 4;
    float ERR_ANIMATOR				= 5;
    float ERR_ID					= 6;
    float ERR_TARGET				= 7;
    float ERR_TARGETNAME			= 8;
    float ERR_STATIC_NOMODELPATH	= 9;
    float ERR_NOHEALTH_DMG			= 10;
    float ERR_HEALTH_NODMG			= 11;
    float ERR_VIEW_OFS				= 12;
    float ERR_URGENT				= 13;
    float ERR_NOINTERFACE			= 14;
    float ERR_INTERFACEONLY			= 15;
    float ERR_PNTS					= 16;
    float ERR_WEAPON				= 17;
    float ERR_PASSEDFLOOR			= 18;
    float ERR_NODATA2WRITE			= 19;
    float ERR_MOVEDIR				= 20;
    float ERR_SPEED					= 21;
    float ERR_NODIMS				= 22;
    float ERR_TYPE					= 23;
    float ERR_NOTARGETS				= 24;
    float ERR_GROUP					= 25;
    float ERR_GROUPNAME				= 26;
    
    void(float err) ThrowException =
    {	//hint to the object
    	dprint("\n\n");
    	dprint("GNOME PHUQUP: an exception was thrown by: ");
    	dprint(self.classname);
    	dprint(" at: ");
    	dprint(vtos(self.origin));
    	dprint("\n");
    	
    	switch(err)
    	{	case ERR_GNOMENAME:
    			dprint("ERR_GNOMENAME: It is mandatory to set the classname field.\n");
    			break;
    		case ERR_MODELPATH:
    			dprint("ERR_MODELPATH: It is mandatory to set the model field.\n");
    			break;
    		case ERR_SOUNDPATH:
    			dprint("ERR_SOUNDPATH: It is mandatory to set the sound field.\n");
    			break;
    		case ERR_EFFECTNAME:
    			dprint("ERR_EFFECTNAME: It is mandatory to set the effectname field.\n");
    			break;
    		case ERR_ANIMATOR:
    			dprint("ERR_ANIMATOR: It is mandatory to set the animator field.\n");
    			break;
    		case ERR_ID:
    			dprint("ERR_ID: It is mandatory to set the id field.\n");
    			break;
    		case ERR_TARGET:
    			dprint("ERR_TARGET: It is mandatory to set the target field.\n");
    			break;
    		case ERR_TARGETNAME:
    			dprint("ERR_TARGETNAME: It is mandatory to set the targetname field.\n");
    			break;
    		case ERR_STATIC_NOMODELPATH:
    			dprint("ERR_STATIC_NOMODELPATH: You tried to turn an empty into a static. set the model field.\n");
    			break;
    		case ERR_NOHEALTH_DMG:
    			dprint("ERR_NOHEALTH_DMG: You gave a damagable entity no health.\n");
    			break;
    		case ERR_HEALTH_NODMG:
    			dprint("ERR_HEALTH_NODMG: You gave health to a non-damagable entity.\n");
    			break;
    		case ERR_VIEW_OFS:
    			dprint("ERR_VIEW_OFS: It is mandatory to set the view_ofs field.\n");
    			break;
    		case ERR_URGENT:
    			dprint("ERR_URGENT: This entity is being instantiated by an incompatible entity.\n");
    			break;
    		case ERR_NOINTERFACE:
    			dprint("ERR_NOINTERFACE: This entity cannot be subclassed in another entity.\n");
    			break;
    		case ERR_INTERFACEONLY:
    			dprint("ERR_INTERFACEONLY: This entity must be subclassed in another entity.\n");
    			break;
    		case ERR_PNTS:
    			dprint("ERR_PNTS: It is mandatory that both the mins and maxs fields are set.\n");
    			break;
    		case ERR_WEAPON:
    			dprint("ERR_WEAPON: This entity must be subclassed in another entity.\n");
    			break;
    		case ERR_PASSEDFLOOR:
    			dprint("ERR_PASSEDFLOOR: It is mandatory that both the mins and maxs fields are set.\n");
    			break;
    		case ERR_NODATA2WRITE:
    			dprint("ERR_NODATA2WRITE: There was no data to write to the file.\n");
    			break;
    		case ERR_MOVEDIR:
    			dprint("ERR_MOVEDIR: The movedir field was not set for this entity.\n");
    			break;
    		case ERR_SPEED:
    			dprint("ERR_SPEED: There was no speed set for this entity.\n");
    			break;
    		case ERR_NODIMS:
    			dprint("ERR_NODIMS: This entity has no dimensions.\n");
    			break;
    		case ERR_TYPE:
    			dprint("ERR_TYPE: It is mandatory that the type field is set for this entity.\n");
    			break;
    		case ERR_NOTARGETS:
    			dprint("ERR_NOTARGETS: It is mandatory that this entity have available targets.\n");
    			break;
    		case ERR_GROUP:
    			dprint("ERR_GROUP: It is mandatory that the group field is set for this entity.\n");
    			break;
    		case ERR_GROUPNAME:
    			dprint("ERR_GROUPNAME: It is mandatory that the groupname field is set for this entity.\n");
    			break;
    		default:
    			dprint(ftos(err));
    			dprint(" is not a recognized error number.\n");
    			break;
    	}
    	
    	self.urgent = err;
    }
    
    // Gypsy - force a structure into the code
    // factor = 0: The entity canNOT be included in another entity
    // factor = 1: The entity can ONLY be included in another entity
    void(string match, float factor) InstanceRules =
    {	if(!factor)
    	{	if(self.classname != match)
    		{	ThrowException(ERR_NOINTERFACE);
    			self.urgent = ERR_NOINTERFACE;
    			return;
    		}
    	} else {
    		if(self.classname == match)
    		{	ThrowException(ERR_INTERFACEONLY);
    			self.urgent = ERR_INTERFACEONLY;
    			return;
    		}
    	}
    }
    
    //	Gypsy:Gnome - Notification Manager | build 20130513-12:37cn
    float WARN_GNOMENAME 		= 1;
    float WARN_MODELPATH 		= 2;
    float WARN_SOUNDPATH 		= 3;
    float WARN_EFFECTNAME		= 4;
    float WARN_ANIMATOR			= 5;
    float WARN_ID				= 6;
    float WARN_TARGET			= 7;
    float WARN_TARGETNAME		= 8;
    float WARN_STATIC_EFFNAME	= 9;
    float WARN_SOLID			= 10;
    float WARN_SOLIDNOT_HEALTH	= 11;
    float WARN_HEALTH_NODMG		= 12;
    float WARN_TAKEDAMAGE		= 13;
    float WARN_MOVETYPE			= 14;
    float WARN_VOLUME			= 15;
    float WARN_ATTENUATION		= 16;
    float WARN_VIEW_OFS			= 17;
    float WARN_OVERRIDE_PNTS	= 18;
    float WARN_ABS_PNTS			= 19;
    float WARN_FILE				= 20;
    float WARN_FILE_READ		= 21;
    float WARN_FILE_COMPLETE	= 23;
    float WARN_DMGSETNO			= 24;
    float WARN_ORFIELDSPREAD	= 25;
    
    //returns the appropriatre string back to an array index that matches the warning number
    string(float info) get_notice =
    {	local string temp;
    	temp = string_null;	//compiler
    	switch(info)
    	{	case WARN_GNOMENAME:
    			temp = "gnomename field has not been set.\n";
    			break;
    		case WARN_MODELPATH:
    			temp = "model field has not been set. this entity must be a brush or empty. \n";
    			break;
    		case WARN_SOUNDPATH:
    			temp = "sound field has not been set.\n";
    			break;
    		case WARN_EFFECTNAME:
    			temp = "effectname field has not been set.\n";
    			break;
    		case WARN_ANIMATOR:
    			temp = "no animator was assigned.\n";
    			break;
    		case WARN_ID:
    			temp = "id field has not been set.\n";
    			break;
    		case WARN_TARGET:
    			temp = "target field has not been set.\n";
    			break;
    		case WARN_TARGETNAME:
    			temp = "targetname field has not been set.\n";
    			break;
    		case WARN_MOVETYPE:
    			temp = "movetype field was not set and defaulted to MOVETYPE_NONE.\n";
    			break;
    		case WARN_TAKEDAMAGE:
    			temp = "takedamage field was not set and defaulted to DAMAGE_NO.\n";
    			break;
    		case WARN_SOLID:
    			temp = "solid field was not set and defaulted to SOLID_NOT.\n";
    			break;
    		case WARN_VIEW_OFS:
    			temp = "view_ofs has not been set. the eye level of your model is assigned to it's origin point.\n";
    			break;
    		case WARN_VOLUME:
    			temp = "volume field was not set and defaulted to 0.5\n";
    			break;
    		case WARN_ATTENUATION:
    			temp = "attenuation field was not set and defaulted to ATTN_NONE\n";
    			break;
    		case WARN_STATIC_EFFNAME:
    			temp = "you cannot set an effect on static entities. your entity was defaulted to SOLID_NOT and MOVETYPE_NONE to allow the effect.\n";
    			break;
    		case WARN_SOLIDNOT_HEALTH:
    			temp = "you have health on a SOLID_NOT\n";
    			break;
    		case WARN_OVERRIDE_PNTS:
    			temp = "you are overriding the absmin/max properties.\n";
    			break;
    		case WARN_ABS_PNTS:
    			temp = "you are using absmin/max values for your bbox. \n";
    			break;
    		case WARN_FILE:
    			temp = "some file interaction didn't complete. \n";
    			break;
    		case WARN_FILE_READ:
    			temp = "couldn't read the file data \n";
    			break;
    		case WARN_FILE_COMPLETE:
    			temp = "the file interaction completed successfully. \n";
    			break;
    		case WARN_HEALTH_NODMG:
    			temp = "you have health on a non-damageable entity. \n";
    			break;
    		case WARN_DMGSETNO:
    			temp = "DAMAGE_NO was set for this entity. \n";
    			break;
    		case WARN_ORFIELDSPREAD:
    			temp = "you are overriding the default .fieldspread. \n";
    			break;
    	}
    	if(temp != string_null) self.notify[0] = "1";
    	else temp = strcat("A notification number that does not exist [", ftos(info), "] was attempted here.\n");
    	
    	return temp;
    }
    
    /*
    	I use an array here because treating it like a flag made the number rack up too fast.
    	Now I can count in succession and keep the value very low.
    */
    void(float info) manage_notifications = 
    {	cfg_var = CFG_ALLOW_NOTIFY;
    	if( self.cfg_notify && cfg_var && !check_string(self.notify[info]) )
    	{	self.notify[info] = get_notice(info);
    	}
    };
    
    string(string file, float typ, string str) file_manager =
    {	cfg_var = CFG_WRITE_LOGS; 	//constants can't be placed directly into a conditional without a compiler warning
    								//so let's assign the value to a global float and use that instead
    	if(!cfg_var)
    	{	str = string_null;						
    		FILES_WRITABLE = 0;
    	} else {
    		local float fhandle = fopen(file, typ);//open a file
    		if(!fhandle)
    		{	str = string_null;
    			manage_notifications(WARN_FILE);  	//it's not a crisis so we just add it to notify[WARN_FILE]
    												//notify[] should be empty - either it was wiped or never existed
    												//this means WARN_FILE should now be the only notice
    			FILES_WRITABLE = 0;					//turn off writing 
    			ThrowNotifications();				//send the report to the console, which will not try to write again
    												//ending any possible loop.
    		} else {
    			if(typ < 1)
    			{	str = fgets(fhandle);
    				if( !check_string(str) )
    				{	manage_notifications(WARN_FILE_READ);
    					FILES_WRITABLE = 0;	
    					ThrowNotifications();
    				}
    			} else {
    				if( check_string(str) )
    				{	fputs(fhandle,str);
    					manage_notifications(WARN_FILE_COMPLETE);
    					FILES_WRITABLE = 0;	
    					ThrowNotifications();
    				}
    				else ThrowException(ERR_NODATA2WRITE);
    			}
    			fclose(fhandle);					//close the file
    			if(!FILES_WRITABLE) FILES_WRITABLE = 1;	//turn writing back on
    		}
    	}
    	return str;
    };
    
    //prints a header and then spits out every stored notification
    void() ThrowNotifications = 
    {	local string temp;
    	temp = string_null;
    	if ( check_string(self.notify[0]) )
    	{	//hint to the object
    		temp = strcat("\n\nGNOME NOTIFIER: accumulated field notifications for ",self.classname," at: ",vtos(self.origin),"\n");
    		
    		local float i;
    		for (i=1; i<32; ++i)
    		{	if( check_string(self.notify[i]) )
    			{	temp = strcat(temp,self.notify[i]);		//building log string
    				self.notify[i] = string_null;			//reset
    			}
    		}
    		dprint( strcat(temp,"\n") );
    	}
    	cfg_var = CFG_WRITE_LOGS;
    	if(FILES_WRITABLE && cfg_var)
    		file_manager("notify.txt", FILE_APPEND, temp);
    }
    I'll be honest, a lot of this is still over my head.
    I do have some background in C, but that only because I recently read the "C guide for dummies." It was surprisingly good, I'm going to be re-reading it soon. You gotta start somewhere.

    This looks like really good stuff MadGypsy. I'll be using it as a resource as get better. Thank you for sharing, it looks amazing.
    I'm still waiting for the official release of Qung Fu...

    Comment


    • #17
      Last one. Here is a concept for you.

      Code:
      // Gypsy: find and return the power of the flag value
      float(float fl) index = 
      {	local float i;
      
      	//FFwd ->>
      	i = ceil( ( strlen( ftos(fl) ) - 1 ) * 3.33 ); 
      	
      	//this will only have to run a maximum of 3 times to hit the number
      	while(pow(2,i) < fl){ i++; } 			
      	
      	return i;
      };
      The implication here is to make associative arrays. For instance you could designate some flag constants and they can be used to label arrays indexes. The purpose of using a flag is that flag can also be used as a flag normally would, meaning that essentially you could record entity values in an array for use somewhere else.

      Code:
      float MY_FLAG = 2;
      float MY_OTHER_FLAG = 4;
      float A_BUNCH_OF_FLAGS_LATER = 256;
      
      float someArray[32];
      
      someArray[index(A_BUNCH_OF_FLAGS_LATER)] = someValue;
      As far as FFwd->> goes. I just figured out a constant algorithm that gets the start index within 3 increments of the final answer. It is a nutty formula based on the amount of numbers in the flag (ie 128 = ceil((3-1)*3.33)=7^2=12 and then 3.33 turned out to be the magic number to get it really close every time without ever going over. Probably because power only hold their character count for 3 powers.

      2, 4, 8
      16, 32, 64
      128, 256, 512
      1024, 2048, 4096, 8192 <- hah, well until here. It probably gets worse. Whatevs, the index is still fast forwarded without going over. It would skip 9 numbers in this case. Meaning the while has to run 9 less times. As the flag numbers increase those skips ahead could become substantial.

      @use as a resource
      This isn't even close to all of the code. Code like this will have to be compiled with FTEQCC, because of the array.

      @your sig - QuakeKid
      That makes me hella uncomfortable, bro. I mean, thank you but, that isn't necessary. how about, "I'm just like MadGypsy, except Imma finish my custom QC." or something entirely different altogether? If you are reading books on C programming and calling them "good" (like you just watched an action thriller or summin) then you probably aren't dumb at all. I dont care if the book was C for Complete Fucking Idiots. Complete fucking idiots can't program in C so.....
      Last edited by MadGypsy; 04-29-2015, 08:37 PM.
      http://www.nextgenquake.com

      Comment


      • #18
        Originally posted by golden_boy View Post
        A frame is a render frame. The engine renders x frames per second, and each frame these functions are run. (edit: I might actually have misremembered this, it might just be a server frame or something since the progs.dat runs on the server of course, not on the client. I hope Spike or someone like that will clarify it.)

        Player Pre Think is a function called at the start of every frame, Player Post Think at the end.

        That's all there is to it.

        You can use these functions to do stuff that should be run every frame (i.e. continuously), such as checking whether the player is in water or whatever.

        Animation in Quake is done at 10 frames per second, which is why interpolation is needed at higher frame rates to make the animations look smooth. All the animation macros in the monster code assume a speed of 10 fps. Ancient, I know.

        Edit: IIRC main() is never actually run in qc.

        Edit 2: Why are you trying to write a progs.dat from scratch? Isn't that kinda brutal?

        Edit 3: And before you ask, the QC source is full of functions that are never called from another function - monster_ogre() and such. These functions contain monster spawn directions and similar stuff, they are spawn functions that get called when a map file is loaded. If the map has a monster_ogre entity, monster_ogre() in the qc gets called to set it up with the origin etc supplied by the map.
        Tell me something Golden Boy, could I use PlayerPreThink or PlayerPostThink to do the following:

        If someone logs in, let’s say his name is B0rk… and I don’t like B0rk… I don’t like B0rk at all. Could I can make their name a trigger, and the moment they touch water, (or teleport, or singe themselves in lava, or get hit by a tomato) their ::face explodes:: or something like that?

        I have... high hopes for this-ism.
        I'm still waiting for the official release of Qung Fu...

        Comment


        • #19
          using floats to refer to strings is silly, just pass the string directly. this also means you can use strcat/sprintf/whatever to provide extra info about the error. plus it means the code is more readable too, and you can more easily find the bit of code that triggers the error instead of having to find the bit of code that prints it and THEN the bit of code that triggers it.

          over-complicated code is your biggest enemy.
          regarding bitflags and arrays, often you'll find it easier to do it the other way around. use bitshifts instead of trying to figure out what the bit index should be from a bit value.
          tbh I'm not sure why you'd be doing that sort of thing anyway.
          try to avoid arrays, they're typically emulated, and globals. globals are a poor programming practise, and thus evil.
          Some Game Thing

          Comment


          • #20
            I actually know most of that now. I wrote this code 2 years ago. I don't really remember why I wanted the idea that I posted here. If I remember at all, I want to say I was thinking that individual monster classes could be eliminated by letting you set animations within array values....in the map.

            Never forget that part cause it is very important. The main idea behind this rewrite was to utilize the fuck out of the map entity inspector, have a more generic code base and use the map to truly define your entities. So something like this was probably where I was going. Maybe not with flags though for this way of using it.
            Code:
            float WALK_START = 1;
            float WALK_END = 2;
            
            ...
            
            
            summin with animation[WALK_START] where animation was defined in the entity inspector.
            I'm not saying it was genius or anything but, I believe this is basically where I was going with this. Actually I just looked at the ent that I posted below and apparently the array was going to be "animator" hence it's string value that I could csv or whatever to concoct the array.

            @overcomplicated worst enemy

            Yeah, I agree with that. Whatever I was doing with this at the time I know it at least seemed like the only way to accomplish the task from the end of the information coming from the map. Actually, there is no doubt it was the cleanest looking way. The alternative would have been to turn the .ent into a ridiculous list of animation properties for every animate-able thing.

            Really, even though I am sure there is some reason that contouring your specific entity in the map editor is bad or whatever... I built an entire really working elevator using this method. It stopped on floors and could be called and everything. There was no specific elevator code. There was move_brush code but move_brush is ANY brush that can move. Door, plat, lift, anything you want... even a fully functioning elevator, with buttons that were move_brush as well. You can literally invent entities in the map. very complicated ones.

            That's also why this project was named Gnome. You put a bunch of mostly generic "gnomes" in the map and you can turn them into all kinds of stuff. Like the gnomes you see in the corner of your eye but when you turn your head they disappear behind "stuff". Maybe they disappeared into the "stuff", and that's basically what the gnomes in my map do. You could even make gnome particle clouds.

            What else could you expect from a guy that loved radiant and knew qc pretty fair? Of course after tearing apart the entire back-end of possibilities in radiant, the logical next step was to make a "base game" & game pack that made radiant the game studio. I would have done it too if it weren't for you meddling kids and that stupid dog... lol
            Last edited by MadGypsy; 04-29-2015, 09:46 PM.
            http://www.nextgenquake.com

            Comment


            • #21
              pbbbbbbt.... I can't believe I found this. My complete elevator logic. 2 of the obj_'s in the upper left use move_brush for their logic and individually they could be used for other purposes. The other one is just a fancy info_null

              http://www.nextgenquake.com

              Comment


              • #22
                Getting back to StartFrame and Pre/PostThink: it might help to recall that if you were to completely freeze/pause a Quake server mid-game, the players' locations would be fixed. A player could be stuck midair, for example, like a single cartoon frame. Yet during regular gameplay, the numbers representing a player's location (in quakec this is the .origin field) change according to physics calculations (like gravity) and player input. This means it's actually quite similar to a cartoon, since a player exists frame by frame in slightly changing locations (say, heading towards the ground).

                Anyway, the server does this physics stuff and it will call those functions you named to allow quakec code to control particulars of your choosing, dependent if you want physics effects in your logic or not. The way it looks is like so, multiple times a second:

                StartFrame()
                PlayerPreThink() <-- player #1 is entity self
                PlayerPreThink() <-- player #2 is entity self
                PlayerPreThink() <-- etc
                [Internal server math moves everything slightly, if it should be moving, plus more]
                PlayerPostThink() <-- player #1 is entity self
                PlayerPostThink() <-- player #2 is entity self
                PlayerPostThink() <-- etc

                I believe after all this is done, the server tells all the players their new locations (as well as rockets, grenades, monster, etc). However, there is a big caveat, since this is hardly the only way that the server and quakec interact, but it is the answer to your question.

                I also noted that your description of ClientKill() is off. It turns out this function is called when a player does the "kill" command in the console. A player expects to die when doing this command, so the function should do that, but it's not typically used.

                Comment


                • #23
                  Originally posted by QuakeKid View Post
                  Tell me something Golden Boy, could I use PlayerPreThink or PlayerPostThink to do the following:

                  If someone logs in, let�s say his name is B0rk� and I don�t like B0rk� I don�t like B0rk at all. Could I can make their name a trigger, and the moment they touch water, (or teleport, or singe themselves in lava, or get hit by a tomato) their ::face explodes:: or something like that?

                  I have... high hopes for this-ism.
                  I don't know much about multiplayer stuff, my coding always concerned itself with singleplayer things such as map entities and other stuff that is practical for SP mod making, such as HUDs and inventories and weapons and monsters and physics and AI and whatnot.
                  Scout's Journey
                  Rune of Earth Magic

                  Comment


                  • #24
                    assuming you know for a fact what their name will be..yes.
                    anywhere anything happens check netname.

                    for the water example, you'd probably want to edit watermove, because otherwise you'd need to change the touch function of every water brush (which you could also do).

                    in watermove, put in

                    Code:
                    if(self.netname == "derpface"){stuffcmd(self, "kill\n");}
                    that will make the player suicide.
                    Gnounc's Project Graveyard Gnounc's git repo

                    Comment


                    • #25
                      Originally posted by Zop View Post
                      Getting back to StartFrame and Pre/PostThink: it might help to recall that if you were to completely freeze/pause a Quake server mid-game, the players' locations would be fixed. A player could be stuck midair, for example, like a single cartoon frame. Yet during regular gameplay, the numbers representing a player's location (in quakec this is the .origin field) change according to physics calculations (like gravity) and player input. This means it's actually quite similar to a cartoon, since a player exists frame by frame in slightly changing locations (say, heading towards the ground).

                      Anyway, the server does this physics stuff and it will call those functions you named to allow quakec code to control particulars of your choosing, dependent if you want physics effects in your logic or not. The way it looks is like so, multiple times a second:

                      StartFrame()
                      PlayerPreThink() <-- player #1 is entity self
                      PlayerPreThink() <-- player #2 is entity self
                      PlayerPreThink() <-- etc
                      [Internal server math moves everything slightly, if it should be moving, plus more]
                      PlayerPostThink() <-- player #1 is entity self
                      PlayerPostThink() <-- player #2 is entity self
                      PlayerPostThink() <-- etc

                      I believe after all this is done, the server tells all the players their new locations (as well as rockets, grenades, monster, etc). However, there is a big caveat, since this is hardly the only way that the server and quakec interact, but it is the answer to your question.

                      I also noted that your description of ClientKill() is off. It turns out this function is called when a player does the "kill" command in the console. A player expects to die when doing this command, so the function should do that, but it's not typically used.
                      Thanks for the clarification Zop, it really helps get things straight in my head. I'll update the ClientKill definition too, Thank you!

                      Originally posted by gnounc View Post
                      assuming you know for a fact what their name will be..yes.
                      anywhere anything happens check netname.

                      for the water example, you'd probably want to edit watermove, because otherwise you'd need to change the touch function of every water brush (which you could also do).

                      in watermove, put in

                      Code:
                      if(self.netname == "derpface"){stuffcmd(self, "kill\n");}
                      that will make the player suicide.
                      Excellent. Thanks gnounc, all my plans are possible.
                      I'm still waiting for the official release of Qung Fu...

                      Comment


                      • #26
                        Next Question.

                        If I wanted to look up all options for a function, and read the function itself (within or without of the Quake infrastructure) how do I do that?

                        For instance: self
                        It has all kinds of extensions and ways to instantiate.

                        For example:
                        self.classname
                        self.health
                        self.max_health
                        self.takedamage
                        self.solid

                        Is there a resource where I can look each option up? I want to know what it is and what it can do.


                        EDIT: ...and then I want to pee on it and mark it my territory.
                        I'm still waiting for the official release of Qung Fu...

                        Comment


                        • #27
                          what you are calling options are called fields. I'm gonna make it easy for you. All globally declared fields are on every self. So mostly just read defs qc. When a field is created ALL ENTITIES adopt that field.

                          fields are any type which is declared with a preceeding dot.
                          .float, .string , etc

                          Originally posted by defs.qc
                          .float modelindex; // *** model index in the precached list
                          .vector absmin, absmax; // *** origin + mins / maxs
                          .float ltime; // local time for entity
                          .float movetype;
                          .float solid;
                          .vector origin; // ***
                          .vector oldorigin; // ***
                          .vector velocity;
                          .vector angles;
                          .vector avelocity;
                          .vector punchangle; // temp angle adjust from damage or recoil
                          .string classname; // spawn function
                          .string model;
                          .float frame;
                          .float skin;
                          .float effects;
                          .vector mins, maxs; // bounding box extents reletive to origin
                          .vector size; // maxs - mins
                          .void() touch;
                          .void() use;
                          .void() think;
                          .void() blocked; // for doors or plats, called when can't push other
                          .float nextthink;
                          .entity groundentity;
                          .float health;
                          .float frags;
                          .float weapon; // one of the IT_SHOTGUN, etc flags
                          .string weaponmodel;
                          .float weaponframe;
                          .float currentammo;
                          .float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
                          .float items; // bit flags
                          .float takedamage;
                          .entity chain;
                          .float deadflag;
                          .vector view_ofs; // add to origin to get eye point
                          .float button0; // fire
                          .float button1; // use
                          .float button2; // jump
                          .float impulse; // weapon changes
                          .float fixangle;
                          .vector v_angle; // view / targeting angle for players
                          .float idealpitch; // calculated pitch angle for lookup up slopes
                          .string netname;
                          .entity enemy;
                          .float flags;
                          .float colormap;
                          .float team;
                          .float max_health; // players maximum health is stored here
                          .float teleport_time; // don't back up
                          .float armortype; // save this fraction of incoming damage
                          .float armorvalue;
                          .float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes
                          .float watertype; // a contents value
                          .float ideal_yaw;
                          .float yaw_speed;
                          .entity aiment;
                          .entity goalentity; // a movetarget or an enemy
                          .float spawnflags;
                          .string target;
                          .string targetname;
                          .float dmg_take;
                          .float dmg_save;
                          .entity dmg_inflictor;
                          .entity owner; // who launched a missile
                          .vector movedir; // mostly for doors, but also used for waterjump
                          .string message; // trigger messages
                          .float sounds; // either a cd track number or sound number
                          .string noise, noise1, noise2, noise3; // contains names of wavs to play
                          and

                          Originally posted by defs.qc
                          .void() th_stand;
                          .void() th_walk;
                          .void() th_run;
                          .void(entity attacker, float damage) th_pain;
                          .void() th_die;
                          .void() th_missile;
                          .void() th_melee;
                          and

                          Originally posted by defs.qc - expected by engine
                          noref .string wad, map, mdl, killtarget;
                          noref .entity trigger_field;
                          noref float skill;
                          noref .float worldtype, delay, wait, lip, light_lev, speed, style, dmg, attack_finished, cnt, count, state, jump_flag, walkframe;
                          noref .vector pos1, pos2, mangle, finaldest, finalangle, dest;
                          That pretty much covers it. When I say all fields go to all entities I want to be real clear.

                          func_plat.walkframe exists. You'll never use it but func_plat is an entity and walkframe is a field so,... it exists.
                          Last edited by MadGypsy; 05-01-2015, 12:04 PM.
                          http://www.nextgenquake.com

                          Comment

                          Working...
                          X