QuakeWiki
August 15, 2018

Search And Rescue (search-based learning)

Article by MadGypsy

I am going to teach you how to teach yourself. It’s supposedly a “fact” that you have to tell someone something 7 times before they officially commit it to memory, so, I’m going to make this tutorial 7 repetitions.First of all, I am using Notepad++ for this tutorial. It’s free and it’s awesome. You should go get it so you can have this invaluable tool at your disposal.

In notepad++ I opened every single .QC that I have, all at one time. I then randomly clicked a tab and “threw” the scrollbar. I wound up on the LaunchMissle function in Wizard.qc. I then started at the top of the function and read until I hit something I didn’t know (it didn’t take long).

Research level: 1

As you can see I have makevectors highlighted in the image. Of course I understand what something so accurately named is doing, but I want to know how it works. So, I highlighted it, clicked search (in the top bar) and then chose find. Notepad++ automatically places my selection in the find box, so I just clicked find all in all opened documents. The results were what you see at the top of the image.

We get a nice little chunk of info. From what I highlighted in grey, we can see that makevector sets v_forward, v_up and v_right, but just as important – those three vars are not field types (there is no dot before the vector type). So this means that these vars are global and not a declared property of any specific entity.

However, there is even more info in that little gray hilight. You see how makevectors = #1. This means that makevectors is a built-in function. In other words, make vectors is used by the quake c code, but it is processed and defined in whatever engine you use. Not only is it a built-in function, but it is the first one. Which actually means little more than you are learning them in order. (lol)

Let’s go ahead and polish off our line by doing a find all in all opened documents for angle and see what else it can tell us

Research level: 2

Well, there isn’t a whole lot there. Lets address a few other things. When I do the document-wide searches, I am scrolling through the results looking for DEFS.qc. This is the .qc where the grand majority of Quakes variables are defined. I don’t just rush to DEFS.qc. I scan all the other results on the way.

Scanning, that is a nice segue to the next thing we will address. Scan down to the bottom of the results and you will see self.mangle = self.angles. Mangle eh, what is that? Let’s find out. We can click that line in the search results and it will bring us directly to that line in the .qc. Once I was brought to the line, I hilighted mangle, clicked search and selected find -> find all in all opened documents.

Research level: 3

When the search results appeared, on my way to DEFS.qc, I came across this line (hilighted in the results). It piqued my interest and I found myself in TRIGGERS.qc (this is kinda like a nerd adventure…right? LOL). Now, I already knew that “t” was going to be an entity, because it has a field property. Only entities have field types. However, I wanted to know – what is this “t” they speak of.

Well, first off the function is teleport_touch. Can you guess what this function is for o.0? The first occurence of “t” (aside from being declared a local entity) is when it is being assigned the return value of the “find” method. Obviously “find” is going to return an entity, but there is something very strange here. If you scan up you will see a line that is wrapping self.targetname in an if statement. This is because targetname is a field property of an entity. To make it simple – it is the entitiy’s unique name*. The problem is, in our find function, targetname is not joined to an entity.

Strange indeed we will have to remember to research this at another level. For now though, we still need to figure out what a mangle is. Off to DEFS.qc.

*unique name/targetname: when you build maps, in order to determine one object from another, you give entities unique names. These names can be anything the mapper wants them to be. Their sole purpose is to distinguish them from other entities of the same type. So let’s assume that you have a trigger that opens a door. Well you don’t want the trigger to open every door, so you give the door a targetname and then put that name in the triggers target field. That’s how entities are connected and “talk” to each other.

Research level: 4

Jackpot! Man, ya’ gotta love well commented code. It’s right there above the mangle declaration. Mangle holds the variables for pitch, yaw and roll. Since that was so quick and awesome that it stole my thunder for this research level, lets have a chit chat about vectors. So far, we have come across quite a few varieties of vectors and vector processors. It all started with makevectors, which takes the players current angles and sets the global vars v_forward, v_up and v_right. We have to assume that these vars are just place holders that are ready for any entity that needs to use them.

We have also come across mangle which sets the pitch yaw and roll. There is another often-used field type vector named origin. Now, vectors have a neat little feature. You can capture any property of a vector with what I call underscore syntax. Let’s take angles for instance, we can capture the x property of angles with angles_x. The same goes for the y and z property. Origin and other vectors can be treated the same, EXCEPT mangle!

We got our answer on mangle really quick, but what the search results didn’t show is the line directly above it. In this case (as it turns out) mangle is used to set the pitch yaw and roll of the INTERMISSION CAMERA. Now, this isn’t it’s only use, after all, we were in TRIGGERS.qc and mangle was being calculated from info_teleport_destination -oops you weren’t supposed to know that yet. Forget I said that. Crap! now you are probably calculating the use of pitch yaw and roll from the teleport to the teleport destination. After all you don’t want to teleport laying down…er I mean forget I said all of this .

Upon further research of mangle you find that only some doors, platforms and a few monsters use it (mostly). Anyway, enough about mangle and vectors, we know what they do, They are orientation and position co-ordinates. We have that “find” method that we never researched hanging over our head. Let’s use our handy-dandy document-wide search to see what we can learn

Research level: 5

You still here? Look at you researchin’ and learnin’ and stuff. What, You think you’re smart or somethin’? (LOL). For real though, good job! OK, the find method. When we last left off with this there was an interesting syndrome where we were sticking a naked field type inside of the find method interface. Let’s see if we can figure out why.

Well, a search of targetname just confirms that it is a field type. But look, even more find functions are using the naked version. Lets see if we can figure this out without cheating. Let’s review some facts:

1) the first argument in the find method was world
2) the second argument was targetname which is the unique name of an entity.
3) the third argument was self.target, which is the name of the entity that self is targeting.
4) In this case we know that teleport_touch is self and (because I spilled the beans) we know that “t” is meant to equal the destination based on the return entity of find

Let’s try and turn the statement into English instead of code. Find in the World the targetname that matches the name of self.target. Woah, we did it! That’s the key. In this case targetname is not referring to any certain name, it is telling find to search all the targetnames for the one that matches self.target. We’re awesome!

Let’s see if we are right. Time for another document-wide search.

Research level: 6

Yup! Look, the second parameter of find accepts a string. They even named the var fld (field) AND they used the dot syntax to declare that only a field type string can be used. With more scanning of the search results we find there are other field type strings that are used. Classname is one. Classname is the type of entity something is (monster, door, light, etc) so, in that case it would return a certain kind of entity as opposed to a specifically named one.

Not a bad lesson right? We learned that you don’t always have to put the information of a var in a methods interface. Sometimes it can be simply a var of the correct type and within the method it will be used as a comparison to find things. Like a pointer.

Research level: 7

LOL! Of course our search for something to know would start at practically the next line. What the hell is a mins? Well, according to my document-wide search…

Epilogue

Well, using nothing but an advanced text editor, curiosity and our brain, we were able to take a little journey through the Quake source code and decipher many of its mysteries. Personally, I feel like this method, coupled with using the QC manual is the best way to learn QC.

QC is not a very advanced or complicated language. In many ways it isn’t even as versatile or rich as Javascript. What makes QC confusing is its ambiguous scope and unconventional syntax. Once you learn to decipher the ambiguity and commit the syntax to memory, you will fly as a QC modder.

Thank you for sticking with me for this tutorial,
Gypsy

Post a Comment

No Comments »

No comments yet.

Leave a comment

You must be logged in to post a comment.