Announcement

Collapse
No announcement yet.

Quake Ether

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

  • Quake Ether

    first:
    Originally posted by me
    You're gonna learn abstraction and inheritance and how Quake doesn't have any of that
    That was mellow-drama. QC really doesn't support Object Oriented style inheritance, but it's plenty abstract. The most popular entity in QC is "self". self is nothing, it's also anything, maybe it's everything - if self happens to be world. self is entirely an abstraction, so is other & activator... the list continues and can be expanded. None of these entities have an identity of their own. self inherits the identity of the very first entity to start that chain of processes, unless specifically changed (in QC) to something else along the way. The others are assigned either in QC or by an interaction.

    An example of an interaction would be if you touch a button. The button is self and you are other. You became other by touching the button. That was an interaction. However, it is possible for a monster to be other by touching that same button. So, other is an abstraction of an activator.

    We have only covered 2 pointers (vars) and we have covered every possible entity in the map. Either one of those 2 could be anything. There are more. I won't be covering any more of them here, but they are easy to find. Just go to defs.qc and find everything of the type (.)entity

    ---

    Inheritance works more as an implementation filled with selfs and others. It is that very abstraction that allows us to reuse code across multiple varying types of entities, creating a form of inheritance through implementation. Let's finally look at some code

    Code:
    .string hair;
    .string eyes;
    .float age;
    
    void() Bob =
    {	self.hair = "brown";
    	self.eyes = "brown";
    };
    
    void() Chris = 
    {	Bob();
    	self.age = 37.4;
    };
    So, we called Bob in Chris and because of that Chris now has brown hair and eyes. Was this because Chris inherited the properties of Bob? Well, no, not really. This is where it becomes an inheritance through implementation. Chris called Bob so "self" is Chris. If we called just Bob, Bob would have brown hair and eyes, but since we called Bob in Chris, technically Bob doesn't even exist, all that exists is "self" and self is Chris. Chris did not inherit the properties of Bob he implemented the function of Bob, but through that an inheritance was achieved. The above script is identical to

    Code:
    .string hair;
    .string eyes;
    .float age;
    
    void() Chris =
    {	self.hair = "brown";
    	self.eyes = "brown";
    	self.age = 37.4;
    };
    On the surface this way may actually seem shorter, but you must consider that it is only shorter if everyone is exactly like Chris. If only one thing is different you would have to rewrite everything plus change the one different thing.

    QC is riddled from top to bottom with mass repetition. Every single spot where a model is being instantiated is being done with nearly identical code. Multiple lines of code that are just repeated and repeated, where it could all be turned into one process with some conditions.

    an example.

    Code:
    void() model_instance =
    {	setmodel(self, self.model);
    	setorigin(self, self.origin);
    	setsize(self,self.mins,self.maxs);
    }
    something to note: this is the uber simple version that would work in most cases. There are other things to be considered here but it is beyond the scope of this discussion to hilight them.

    Now, you could call model_instance() in most functions that instantiate a model, instead of the current way, like this

    either
    Code:
    precache_model(self.model);
    model_instance();
    or
    Code:
    model_instance();
    self.model = "";
    What's the difference? The first one would work for actual models (mostly) as well as brushes (like doors) and the second way would be for a brush that you want to have the volume of, but do not want to see the texture of.

    so.. "You're saying you replaced 3 lines with 2...". Yup that's what I'm saying....if all you ever want to do is instantiate one model. However this process can be built upon. Let's consider a possible script flow.

    Code:
    void()model_instance =
    {
    	//makes a model instance
    };
    
    void() typed_instance =
    {	
    	//checks and or sets the solid, movetype, takedamage & health values of any model
    	model_instance();
    };
    
    void() func_field =
    {
    	//set a few constants for this type
    	typed_instance();
    }
    It's QC, we go from the bottom up. func_field only has to set a few values, or make sure they are set, because typed_instance() will determine everything about it's type and state, ending with calling model_instance, which links the model into the world and creates it if necessary.

    So, now I have replaced like 60 lines with 1 (typed_instance()), BUT I have left the door open to bypass typed_instance and go straight for model_instance, should the time arise where typed_instance does not properly check some custom entity I am making.

    QC as it stands now, is a very poor example of how to program. Go open subs.qc - find SUB_CalcMoveEnt and SUB_CalcAngleMoveEnt. Go look at those 2 "different" functions and tell me what's so different about them. They could easily be turned into one code that has a condition for the one line that is actually different. How about:

    Code:
    void(entity ent, vector dest, float tspeed, void() func, float m) SUB_EntMove =
    {	local entity stemp = self;
    	self = ent;
    	if(m)SUB_CalcAngleMove(dest,tspeed,func);
    	else SUB_CalcMove(dest,tspeed,func)
    	self = stemp;
    }
    This would add one more argument to the call, but it would eliminate the need for a duplicate. Now there is only one function that does both jobs. You could expand on the interface as well. What if a model has a spawnflag for rotation

    Code:
    SUB_EntMove(other, other.pos1, 100, callback, (self.spawnflags & ROTATE));
    in this example the rotate flags existance would make m = true and therefore go the AngleMove route. What if I told you that we don't even need all that. What if I told you that 6 functions could be made into 3 and fully decide whether to move origin or angles? I'm not going to teach you that here, but know that subs.qc alone is just a bunch of unnecessary repetition.

    If you want to be good at programming in QC, you should probably start with being good at programming. I hope this discussion has opened your mind to how things could be done more efficiently... less confusingly. What if I told you that I could eliminate 56 functions in QC? How would modding change if there was 56 less duplicate bullshits to worry about? Is there really 56 of them? IDK, I just made that up (so, probably no), but what I'm not making up is the potential for a more streamlined source. I believe that understanding how to fabricate inheritance is the beginning of tapping that potential.

    ~Gypsy

    *inheritance through implementation: that as a phrase is just something I made up that can accurately impress upon you what is happening. That is not a thing you should be trying to act like you know what the f you are talking about... lol. There was no inheritance, so my statement is not accurate in reality. In reality, a chunk of Chris was removed and turned into Bob and then brought back into Chris. It is assumed that Chris had brown hair and eyes regardless of Bob.
    Last edited by MadGypsy; 06-07-2013, 08:16 PM. Reason: self.age - woops
    http://www.nextgenquake.com

  • #2
    while i typically dont understand the majority of what you do i your tuts, i thank you for trying to eduacte the unwashed masses here. so thanks.
    My Avatars!
    Quake Leagues
    Quake 1.5!!!
    Definitive HD Quake

    Comment


    • #3
      Originally posted by MadGypsy
      if my audience is going to be myself, class is over. You decide.
      Dude, stop shouting at us. Have some patience.

      You don't write tutorials to get instantly loved. You write them in the hope that somewhere, sometime, it will be useful to somebody. That might be 5 years from now. You also write them so you can feel like you have sort of done your duty, and made an attempt to at least share your knowledge.

      In short, a tutorial is like a message in a bottle. Don't expect instant hugs and kisses.

      Now for something completely different (the larch!):

      You make some good points; it might interest you that FTEQCC supports classes recently (you probably have to get it from SVN), and a couple people are beginning to work with them.

      I have also been combining and streamlining functions wherever I encounter them. It's something that I do when something stands out particularly. I'll probably go and use classes and inheritance in the future as well.

      I invite you to hang out in #rmq if you're interested.
      Scout's Journey
      Rune of Earth Magic

      Comment


      • #4
        chill
        My Avatars!
        Quake Leagues
        Quake 1.5!!!
        Definitive HD Quake

        Comment


        • #5
          You really sit there and count the number of visitors to your thread? You're neurotic, mate.

          I didn't tell you to fuck off at all. I actually invited you to talk about stuff. But fine, have it your way.
          Scout's Journey
          Rune of Earth Magic

          Comment


          • #6
            Bitmasks

            In this lesson we are going to learn about bitmasks. To properly understand bitmasks, you first need to understand flags and constants.

            Constants

            This is a constant

            Code:
            float SOMEVAR = 1;
            A constant is a variable that has an unchangeable value. It is constant. A constant is created by assigning the value upon declaration (like above) . The following var is not a constant:

            Code:
            float SOMEVAR;
            SOMEVAR = 1;
            It is not a constant because it was assigned it's value after declaration. This means that the value could continue to be reassigned - hence destroying the "constant" of it all.

            It is a fairly standard programming format to type constants in all capital letters. However, typing something in all caps does not make it a constant and using lowercase to declare a constant will make no difference to how it is perceived by the compiler/engine.

            Both of the below are perfectly good constants
            Code:
            float SOMEVAR = 1;
            float somevar = 1;
            Trying to change the value of a constant will result in errors.

            Flags

            Quake uses a system where powers of 2 are stored in a float. The powers of 2 are assigned to constants and then those constants are appended to a holder. Lets make an example of a flag list and then I will be able to better explain it.

            Code:
            float SOMEFLAG = 1;
            float ANOTHERFLAG = 2;
            float ONEMOREFLAG = 4;
            float LASTFLAG = 8;
            First, let me say that a flag value should never be appended twice to a holder. There will never be a time where you could add up all the values and get a wrong answer as long as you don't duplicate a value within it's holder. For instance 1+2 = 3, there is no 3 in the above list. 1 + 2 + 4 = 7 there is no 7 in the above list. However, 2+2 = 4 and that is in the list, which is not what you want if you are looking for 2. You can store all of those flags in one container and mathematically determine the existence of any one of them with bitmasks.

            bitmasks

            To understand bitmasks you have to completely ignore what you think certain characters should mean and accept that they don't mean that. Let's add our holder to the code and get to some examples.

            Code:
            float SOMEFLAG = 1;
            float ANOTHERFLAG = 2;
            float ONEMOREFLAG = 4;
            float LASTFLAG = 8;
            
            .float stored_flags;
            ---

            appending a flag
            Code:
            self.stored_flags = self.stored_flags | ONEMOREFLAG;
            self.stored_flags now equals 4. What the above basically says is:

            "If I do not already have 4 in me, then put 4 in me"

            I know that that doesn't seem logical according to the symbols, but that's what is happening there and that is how you need to do it. I would like to go a bit further though.

            If you did this:

            Code:
            self.stored_flags += ONEMOREFLAG;
            You could potentially be adding that value where it has already been added, now your entire holder is corrupt and unreliable. You may end up with 4+4 in your holder, which is a possible other flag because 8 is a power of 2. Again, we don't want to be making 8 while trying to mess with 4.

            ---

            removing a flag
            Code:
            self.stored_flags -= (self.stored_flags & ONEMOREFLAG);
            The part in parenthesis is the real focus. That part tests to see if the flag exists. If it does exist it returns the value of the flag, otherwise it returns 0. So if stored_flags has the 4 in it, it will return 4 and 4 will be subtracted from the holder value, otherwise 0 is subtracted.

            ---

            removing multiple flags
            Code:
            self.stored_flags -= ( self.stored_flags & ( ONEMOREFLAG | SOMEFLAG | ANOTHERFLAG ) );
            This will test stored_flags for all of those flag values and the ones that are present in stored_flags will be added together and returned. In this case ONEMOREFLAG is the only one that exists (humor me) so 4 will be returned and subtracted from the holder.

            ---

            append multiple flags
            Code:
            self.stored_flags = self.stored_flags | ONEMOREFLAG | SOMEFLAG | ANOTHERFLAG;
            similar to my first example this will check if the values already exist and the ones that don't will get appended to the value of stored_flags.

            _____

            Whereas these are the ways to remove/append flags from a holder. This is not the only implementation for bitmasks. We can use bitmasks to create conditions. Actually the entire point of flags is to create a condition that can be checked to determine an action or effect.

            Here is an example of a bitmask being used as a condition

            Code:
            if(self.spawnflags & DOOR_DONT_LINK)
            {
            //do things if spawnflags has that flag in it
            }
            As I said before, this particular bitmask will return the value if it is present or 0 if it is not. In programming (generally) 0 = FALSE. So, if that flag is not in spawnflags it will be like

            Code:
            if(false)
            {
            
            }
            the only way an if statement will execute is:

            Code:
            if(true)
            {
            
            }
            It is also generally true that anything that is not zero is true. Even though our last bitmask example might return 16, 16 is not false, so it has to be true.


            ~Gypsy
            Last edited by MadGypsy; 06-11-2013, 06:04 PM.
            http://www.nextgenquake.com

            Comment


            • #7
              fteqcc specific operators:
              a |= b; sets flags b in variable a.
              a &~= b; clears flags b in variable a, without affecting others.
              basically its just shorter notation.
              Some Game Thing

              Comment


              • #8
                ooooh thank you! I didn't know you could do that. I'm still glad I explained the long way.

                can you do this

                a |= b| c| d; //add 3 flags

                and/or

                a &~= b| c| d; //subtract 3 flags
                Last edited by MadGypsy; 06-12-2013, 07:45 AM.
                http://www.nextgenquake.com

                Comment


                • #9
                  Even more general... you do not do ANYTHING on the Internet hoping for feedback. It is just for your personal satisfaction, if you get feedback it is even better.
                  Contradiction is truth. Fear is freedom. Rights are privileges. Job is a commodity. Ignorance is strength.

                  Comment


                  • #10
                    Yes it was. Go on, then.
                    Contradiction is truth. Fear is freedom. Rights are privileges. Job is a commodity. Ignorance is strength.

                    Comment


                    • #11
                      Heart to heart

                      We gonna have a little heart to heart. I keep posting QC but I keep getting responses that have nothing to do with it. I FULLY understand that I initially compelled such responses and that's exactly what we are going to talk about. I am going to use a quote by Sylux to make my argument.

                      while i typically dont understand the majority of what you do i your tuts, i thank you for trying to eduacte the unwashed masses here. so thanks
                      The operable statement here is "while i typically dont understand the majority of what you do". Now, this is not to point at Sylux as individual and claim any wrong doing, it is simply that he posted exactly what I needed to make this point.

                      Instead of admitting that the material is "over his head" where is the question that will compel me to write the description that will bring this information to the level of his head? Ya see? When I get aggressive and start making posts about "the lack of responses is bullshit", it is because I KNOW there are more people that feel the way Sylux does but NO ONE is asking the questions that will clarify the data.

                      That's the whole fuckin point. I tell you stuff and then you say "OK, but I don't get this part." So, I elaborate until you do. If you never tell me what it is that you don't understand, I can't help you understand it.

                      I don't write tutorials for 150 people to pass through and achieve confusement. I write tutorials to eliminate all confusion, but I cannot do this is if everyone decides not to participate.

                      I hope this sheds some light on the ABSOLUTE validity of what I said poorly in the beginning.

                      *I know that confusement is not a word. It is now.
                      Last edited by MadGypsy; 06-12-2013, 11:28 AM.
                      http://www.nextgenquake.com

                      Comment


                      • #12
                        Just posting here since I watched the thread.

                        Deleting posts creates a incoherent mess and is not how communication on the internet works.
                        Quake 1 Singleplayer Maps and Mods

                        Comment


                        • #13
                          I'm so glad you said that, cause ya see, this thread is about QC. If the people above me had any respect they would delete their non QC posts and let me have my thread back. I've done it for others before. It's not unheard of. I didn't delete my posts to hide anything or create any messes. I deleted them to get rid of as much bullshit as possible and get back to my QC thread.

                          I'm gonna delete this post and it will be replaced with a tutorial, same for my better worded explanation on participation.

                          If you need what I wrote for history or something, I can go type it all up in another thread for you. But my posts (that remain) here are going to be about QC. And the non QC posts that remain here will remain as a testament to those that only respond to and perpetuate garbage.

                          I think it's funny that you teach someone something and they have nothing to say, but you instigate garbage and you can't get rid of the responders. Every post that is not Sylux or Spirit, is responders to garbage*, where there was plenty of substance to comment on prior to that.

                          *I may have initialized the garbage, but it's still garbage

                          I have an idea where I teach you how to do something and call you a idiot the whole time...that should achieve the proper participation balance. SOmething to learn and something to bitch about.

                          ps "you" does not equal you (whomever you are) specifically

                          aside: The people above me are all trying to convince me that I should do something and expect nothing. I haven't lived the past 38 years of my life with that defeatist mentality and I don't intend to start now. I do something and something is going to fuckin happen, I promise you.
                          Last edited by MadGypsy; 06-13-2013, 06:45 AM.
                          http://www.nextgenquake.com

                          Comment


                          • #14
                            Thanks for taking the time and energy to put this together MG. Not being a C developer some of the syntax was different but I understood the majority of this as the principles of what you were trying to relate are common place in other languages. Plus it was interesting to read. Having digested that and I'm guessing by some of the comments it's unlikely there will be more, I'm just waiting for Rook's mod building tutorial to begin

                            I couldn't help but notice this little gem and say that in general terms it's good advice for anyone trying to contribute in some way
                            Originally posted by golden_boy View Post
                            You don't write tutorials to get instantly loved. You write them in the hope that somewhere, sometime, it will be useful to somebody. That might be 5 years from now. You also write them so you can feel like you have sort of done your duty, and made an attempt to at least share your knowledge.

                            In short, a tutorial is like a message in a bottle. Don't expect instant hugs and kisses.

                            Now for something completely different (the larch!):
                            For some reason I can't +rep him, or you for that matter, but being (cough) over 30 and a python fan since it was first aired I love the python reference

                            Kind regards

                            Monty
                            Last edited by Mr.Burns; 06-16-2013, 06:00 AM.
                            Mr.Burns
                            "Helping to keep this community friendly, helpful, and clean of spammers since 2006"
                            WWW: Quake Terminus , QuakeVoid You Tube: QuakeVoid
                            Servers: Quake.shmack.net, damage.servequake.com

                            News: JCR's excellent ctsj_jcr map is being ported to OOT

                            Comment


                            • #15
                              These tutorials are all primers for R00k if we could stay on topic. I'm teaching you the parts of QC that have a "mystery" to them (aren't obvious). Sel can be very elusive if you don't understand where self is coming from. Spawnflags can also be confusing if you don't understand the synatx. My next tutorial is going to be about time, self.ltime and nextthink.

                              By understanding how these systems work, you wil flyyyyyyyyyyyyyyyy through R00k's tutorials. Not only that but R00k will not have to dumb everything down. I'm getting a lot of flak here, but you people don't understand how far ahead I have already thought this out.

                              This content is not really complicated. Actually QC is lacking so many programming staples that it's like learning half of a language. If I can ever get people to actually ask questions, the content will also improve. I can isolate the pockets of most apparent confusion and eliminate them.

                              What is the point of leaving the thread confused, especially when it is so easy to compel me (or even others) to unconfuse you with a question that explains your confusion?
                              http://www.nextgenquake.com

                              Comment

                              Working...
                              X