]> git.xonotic.org Git - xonotic/xonotic.wiki.git/blobdiff - Introduction-to-QuakeC.md
Upload attachment SpectatorHUD.jpg
[xonotic/xonotic.wiki.git] / Introduction-to-QuakeC.md
index 684a2cdb81971bf9875f16a7ac51587d60ed6ab9..414679b8da9c335580082ccd01346684510f285d 100644 (file)
@@ -1,16 +1,25 @@
 QuakeC
 ======
 
-Article TODO
-------------
-
--   expand explanations
-
 About QuakeC
 ------------
 
 QuakeC is a very simplified dialect of the well-known C programming language, and is used by the Quake I engine and its derivatives. Xonotic uses the GMQCC dialect of QuakeC, so only this dialect will be described (as well as some common extensions among Quake engines).
 
+There are several documents describing the original version of QC as used in Quake 1:
+- an [old version](http://www.gamers.org/dEngine/quake/spec/quake-spec34/index1.htm) which is a part of unofficial [Quake Documentation](http://www.gamers.org/dEngine/quake/spec/quake-spec34/)
+- a probably slightly [newer version](http://www.cataboligne.org/extra/qcmanual.html)
+- a [newer and extended version](http://pages.cs.wisc.edu/~jeremyp/quake/quakec/quakec.pdf) in PDF
+
+Even this page is outdated and incomplete, not all GMQCC QuakeC constructs are described here and some of the bugs mentioned here have already been fixed.
+
+Other resources
+---------------
+
+- [QC Tutorial for Absolute Beginners](https://web.archive.org/web/20091118154016/http://forums.inside3d.com/viewtopic.php?t=1286)
+- [List of builtins on quakewiki.org](https://quakewiki.org/wiki/List_of_builtin_functions)
+- comments and `doc.md` in the `qcsrc/dpdefs` directory
+
 Example code
 ------------
 
@@ -57,17 +66,6 @@ entity findnearestspawn(vector v)
 
 **Note:** *findchain* is implemented in QuakeC for demonstration purposes only so one can see how to build a linked list, as this function is already built in to the engine and can be used directly
 
-Other resources
----------------
-
-Here is a forum on Inside3D where you can read more about QuakeC and ask questions:
--   QuakeC Forum on Inside3D: http://forums.inside3d.com/viewforum.php?f=2
--   QC Tutorial for Absolute Beginners: http://forums.inside3d.com/viewtopic.php?t=1286
-
-For available functions in QuakeC, look in the following places:
--   The Quakery: http://quakery.quakedev.com/qwiki/index.php/List_of_builtin_functions
--   Xonotic source: [builtins.qh](http://git.xonotic.org/?p=xonotic/xonotic-data.pk3dir.git;a=blob_plain;f=qcsrc/server/builtins.qh;hb=HEAD) for Quake functions, [extensions.qh](http://git.xonotic.org/?p=xonotic/xonotic-data.pk3dir.git;a=blob_plain;f=qcsrc/server/extensions.qh;hb=HEAD) for DarkPlaces extensions
-
 Variables
 =========
 
@@ -154,7 +152,17 @@ A *string* in QuakeC is an immutable reference to a null-terminated character st
 
 The offset defines from which starting position to search, and the return value is `–1` if no match is found. The offset returned is *0*-based, and to search in the whole string, a start offset of *0* would be used.
 
--   **substring(string, startpos, length)** returns part of a string. The offset is *0*-based here, too.
+-   **strreplace(old, new, string)** searches for certain characters in a string and replaces them with other characters, as in:
+    ```c
+    strreplace("de", "con", "destruction") == "construction";
+    ```
+
+-   **substring(string, startpos, length)** returns part of a string.
+
+The offset is *0*-based here, too. A length of `-1` designates the end of the string (it will return the part of the string after the start position), a length of `-2` designates the penultimate character of the string, and so on.
+
+-   **strtoupper(string)** capitalizes a string.
+-   **strtolower(string)** lowercases a string.
 
 Note that there are different kinds of *strings*, regarding memory management:
 
@@ -273,7 +281,7 @@ A special kind of functions are the built-in functions, which are defined by the
 string strcat(string a, string b, ...) = #115;
 ```
 
-The function/field syntax is ambiguous. In global scope a declaration can be a variable, field or function. In local scope, it's always a variable. The `var` keyword can be used in global scope to treat is as local scope (always declaring a variable). The following table shows declarations in global scope:
+The function/field syntax is ambiguous. In global scope a declaration can be a variable, field or function. In local scope, it's always a variable. The `var` keyword can be used in global scope to treat it as local scope (always declaring a variable). The following table shows declarations in global scope:
 
 | Example code | Meaning |
 |--------------|---------|
@@ -663,36 +671,127 @@ vectoangles does not match makevectors
 The pitch angle is inverted between these two functions. You have to negate the pitch (i.e. the *x* component of the vector representing the euler angles) to make it fit the other function.
 As a rule of thumb, *vectoangles* returns angles as stored in the *angles* field (used to rotate entities for display), while *makevectors* expects angles as stored in the *v\_angle* field (used to transmit the direction the player is aiming). There is about just as much good reason in this as there is for 1:1 patch cables. Just deal with it.
 
+bound
+-----
+
+A bound is a variable that was previously free, but has been bound to a specific value or set of values. If x > upperlimit the upperlimit is returned, if x < lowerlimit then lowerlimit is returned, if lowerlimit < x < upperlimit then x is returned. That function returns an x value calling this way: 
+```c
+bound(lower_limit, x, upper_limit)
+```
+
+Ternary operator
+----------------
+
+QuakeC allows ternary operators like in C:
+```c
+int a = 2;
+int b = 3;
+int c = 6;
+int d = 8;
+int max = (a > b) ? c : d;
+```
+More [**info**](https://www.geeksforgeeks.org/conditional-or-ternary-operator-in-c-c/).
+
+There is a complex example using `bound` function with this operator:
+```c
+bound(1, ((hunter_count >= 1) ? hunter_count : floor(total * hunter_count)), total - 1);
+bool wholenumber = (hunter_count >= 1) //is hunter count a specified whole number or percentage
+
+if (!wholenumber) //if hunters are defined with percentage count
+{
+ int z = total * hunter_count //wanted percentage amount from total is z
+ int y = floor(z) //round z downwards to nearest whole number
+}
+
+int x = (wholenumber ? hunter_count : y) //if whole number was given use it, 
+//if not use y which is calculated above
+bound(1, x, total - 1) //use the value x if it's above 1 but below (total - 1)
+//Otherwise use the bounding value of that direction to quarantee that 
+//there is always at least 1 hunter and always at least 1 survivor
+```
+
 Entry points
 ============
 
 The server-side code calls the following entry points of the QuakeC code:
 
 -   **void ClientDisconnect()**: called when a player leaves the server. Do not forget to *strunzone* all *strings* stored in the player entity here, and do not forget to clear all references to the player!
+<br />
+
 -   **void SV\_Shutdown()**: called when the map changes or the server is quit. A good place to store persistent data like the database of race records.
+<br />
+
 -   **void SV\_ChangeTeam(float newteam)**: called when a player changes his team. Can be used to disallow team changes, or to clear the player’s scores.
+<br />
+
 -   **void ClientKill()**: called when the player uses the ”kill" console command to suicide.
+<br />
+
 -   **void RestoreGame()**: called directly after loading a save game. Useful to, for example, load the databases from disk again.
+<br />
+
 -   **void ClientConnect()**: called as soon as a client has connected, downloaded everything, and is ready to play. This is the typical place to initialize the player entity.
+<br />
+
 -   **void PutClientInServer()**: called when the client requests to spawn. Typically puts the player somewhere on the map and lets him play.
+<br />
+
 -   **.float SendEntity(entity to, float sendflags)**: called when the engine requires a CSQC networked entity to send itself to a client, referenced by *to*. Should write some data to *MSG\_ENTITY*. *FALSE* can be returned to make the entity not send. See *EXT\_CSQC* for information on this.
+<br />
+
 -   **void URI\_Get\_Callback(...)**:
+<br />
+
 -   **void GameCommand(string command)**: called when the “sv\_cmd” console command is used, which is commonly used to add server console commands to the game. It should somehow handle the command, and print results to the server console.
+<br />
+
 -   **void SV\_OnEntityNoSpawnFunction()**: called when there is no matching spawn function for an entity. Just ignore this...
+<br />
+
 -   **void SV\_OnEntityPreSpawnFunction**: called before even looking for the spawn function, so you can even change its classname in there. If it remove()s the entity, the spawn function will not be looked for.
+<br />
+
 -   **void SV\_OnEntityPostSpawnFunction**: called ONLY after its spawn function or SV\_OnEntityNoSpawnFunction was called, and skipped if the entity got removed by either.
+<br />
+
 -   **void SetNewParms()**:
+<br />
+
 -   **void SetChangeParms()**:
+<br />
+
 -   **.float customizeentityforclient()**: called for an entity before it is going to be sent to the player specified by *other*. Useful to change properties of the entity right before sending, e.g. to make an entity appear only to some players, or to make it have a different appearance to different players.
+<br />
+
 -   **.void touch()**: called when two entities touch; the other entity can be found in *other*. It is, of course, called two times (the second time with *self* and *other* reversed).
+<br />
+
 -   **.void contentstransition()**:
+<br />
+
 -   **.void think()**: described above, basically a timer function.
+<br />
+
 -   **.void blocked()**: called when a *MOVETYPE\_PUSH* entity is blocked by another entity. Typically does either nothing, reverse the direction of the door moving, or kills the player who dares to step in the way of the Mighty Crusher Door.
+<br />
+
 -   **.void movetypesteplandevent()**: called when a player hits the floor.
+<br />
+
 -   **.void PlayerPreThink()**: called before a player runs his physics. As a special exception, *frametime* is set to 0 if this is called for a client-side prediction frame, as it still will get called for server frames.
+<br />
+
 -   **.void PlayerPreThink()**: called after a player runs his physics. As a special exception, *frametime* is set to 0 if this is called for a client-side prediction frame, as it still will get called for server frames.
+<br />
+
 -   **void StartFrame()**: called at the beginning of each server frame, before anything else is done.
+<br />
+
 -   **void EndFrame()**: called at the end of each server frame, just before waiting until the next frame is due.
+<br />
+
 -   **void SV\_PlayerPhysics()**: allows to replace the player physics with your own code. The movement the player requests can be found in the *vector* field *movement*, and the currently pressed buttons are found in various fields, whose names are aliased to the *BUTTON*\_ macros.
--   **void SV\_ParseClientCommand(string command)**: handles commands sent by the client to the server using “cmd ...”. Unhandled commands can be passed to the built-in function *clientcommand* to execute the normal engine behaviour.
+<br />
 
+-   **void SV\_ParseClientCommand(string command)**: handles commands sent by the client to the server using “cmd ...”. Unhandled commands can be passed to the built-in function *clientcommand* to execute the normal engine behaviour.
+<br />
\ No newline at end of file