 First Post!
#1 posted by metlslime [71.202.113.29] on 2007/08/08 05:08:46
So, here's what I'm trying to do right now, and probably nobody knows the answer but here goes. What I'm trying to set up is an entity that emits a constant sound, but is also toggleable. So when you turn it off, the sound goes silent, and when you turn it on, the sound starts up again.
Problem 1: if you are out of hearing range when it turns on, the object will be silent when you get close.
Problem 2: if you save and reload the savegame, the object will be silent.
The basic cause is that sound() calls are fire-and-forget and quake assumes the sounds are short-lived so the above situations won't be much of a problem.
I've tried various solutions, the latest is various versions of "restart the sound every 1 second or so." The problems with that are first, when you approach the object its sound starts up suddenly instead of fading in, and second, you can hear obvious repetition when standing next to the object.
Increasing the frequency of sound() calls reduces the sudden start, but worsens the repetition. I'm going to try and improve this hack by having 3 or four different sounds, and playing them at random, so that you don't hear any obvious repetition of sounds.
#2 posted by necros [99.244.15.189] on 2007/08/08 05:35:35
it is possible, but it's slightly hacky.
unfortunaly, i don't remember who told me about this method... it may have been lordhavoc, but i'm not sure.
anyway, the engine can only load ambient sounds (true ambient sounds that the engine keeps track of regardless of player position) properly when the map is loading up.
you can trick it by using an unused SVC (29). unfortunatly, you can't specify a filename for this, you need to actually feed in the # of the sound in the order as it was loaded into cache. ¬_¬
the best way to do this is to precache your ambient sounds first, this way you don't have to worry about anything being precached before it and mucking up your ambient sounds.
the first sound precaches are located in weapons.qc (W_Precache). load any new ambient sounds in there at the top of the function.
float SVC_SPAWNSTATICSOUND = 29;
Define the constant for convenience, and write a little function to use it:
void(float soundnum, vector org, float ambvolume, float atten) spawnambient =
{
WriteByte(MSG_ALL, SVC_SPAWNSTATICSOUND);
WriteCoord(MSG_ALL, org_x);
WriteCoord(MSG_ALL, org_y);
WriteCoord(MSG_ALL, org_z);
WriteByte(MSG_ALL, soundnum);
WriteByte(MSG_ALL, ambvolume * 255); //translate this into a value between 0 and 255...
WriteByte(MSG_ALL, atten * 64);
};
now just call your new function with whatever sound # you want.
this will spawn a true ambient sound into the map after it was loaded, and won't stop playing when you move out of range.
you'll notice the lack of any channel specification... i'm not sure if it's possible to turn it off again after it's been turned on. i can't check right now, but i'd guess using a non-looping sound will give you that 'non-looping sound for ambient sound' error, since it's not just a normal sound call.
but you will at least be able to turn it on. :x
maybe someone else can build on this?
 Necros....
#3 posted by metlslime [71.202.113.29] on 2007/08/08 09:29:10
Interesting, it would only work if the it could be turned off again somehow. Hmm....
 Also...
#4 posted by metlslime [71.202.113.29] on 2007/08/08 10:07:07
my hack with the multiple random 0.1 sec sound effects works fairly well, but the problem is you can hear a sort of distortion/clip sound when the new sound overrides the old (the same sound you hear when a sound isn't looped correctly, meaning the waveforms don't line up and there's a sort of audio seam.) I may have to live with it. The sound effect for this has a lot of white noise in it (it's a steam jet) but I also wanted to do this for forcefields, and i'm worried that sound won't hide the clipping artifact as well.
 Savegame Function
#5 posted by Preach [86.146.19.13] on 2007/08/08 11:59:20
As it happens I was writing some code yesterday that might help you out. What it does is provides you with a function that is run once when you load a saved game, but not when the game starts first time round. Replace the StartFrame code in world.qc with the following:
nosave float loadflag;
void() LoadGame =
//runs if player has just loaded a game
{
dprint("*****new game loaded******\n");
}
void() StartFrame =
{
teamplay = cvar("teamplay");
skill = cvar("skill");
framecount = framecount + 1;
if ( framecount == 3)
loadflag = 1;//started a new game, not loaded a savegame
else if(!loadflag && framecount > 3)
{
LoadGame();
loadflag = 1;
}
};
You'll need a compiler which supports the nosave keyword for variables, frikqcc and fteqcc are the two I've tried. The idea is that the loadflag isn't saved in the savegame, and so gets reset to 0 when you load a game. The reason you have to wait until the third frame before you set it originally is because when quake loads a savegame, it runs the whole worldspawn procedure to rebuild the precache lists. The worldspawn procedure includes running two game frames, to give things a chance to droptofloor etc. So if you change a nosave variable during those frames, it'll have that value when you load savegames - which might be different to what value it had when you saved - but it's not what we want here.
So that gives you a way to restart the sound after someone loads a game, replace the dprint line in LoadGame with a function that searches for all the sounds that should play and restarts them.
As for the other problem, one possible solution would be to calculate the distance at which the sound can just be heard, assuming you started in range of the sound. Then have the entities search for a player within this radius regularly and start playing when they just enter it. Might be more difficult to make it work in coop.
If you do that, then you don't really want to use findradius for the job, it's a bit excessive to have 10 findradius calls every second per entity if you have a few of these things about. Better to loop through the first maxplayers worth of entities with the nextent command, since the players are always the first entities on the server. Then just test the distance for each of those that turns out to be a player. Whether
vlen(vec) < d
is faster than
vec_x*vec_x + vec_y*vec_y + vec_z*vec_z < d*d
is something I've been meaning to test. One is trying to calculate the square root of a quantity, but it is a builtin, so it's faster than qc code. Probably not necessary to get that kind of saving here if you're testing at most 16 entities, and most of the time just 1, it's just an interesting question.
 Preach....
#6 posted by metlslime [204.15.3.5] on 2007/08/08 20:39:29
yeah, this findradius idea is the direction i'm thinking of going next. One challenge is, the code to play a sound will not bother playing a sound if both right and left stereo channels can't hear it, and the calculation to determine the volume at each "ear" (channel) is somewhat complicated. Not sure if i'll need to recreate that in quakec or if it will suffice to estimate the radius in some other way.
 Toggleable Sound
#7 posted by Mike Woodham [81.158.239.232] on 2007/08/09 00:01:20
The music in FMB_bdg is toggleable and plays everywhere. Being a looped sound, it would play forever if not switched off by the player (by operating the music button) or when the player unwittingly moves through an off-trigger.
It doesn't play from a savegame even if it was playing when the game was saved. But the savegame must be recording the state of the entity because you have to operate the music trigger twice after a savegame if you want the music to play - the first time turns the music off even though you can't hear it, and the second time turns it back on, and you then hear it.
I created the entity following an idea by Preach.
// if the player has not touched the 'toggle-music' button then this must be
// a triggered event, which means....
if (mechanism.classname != "func_button") etc...
Could this be developed to check the state of the entity when opening a saved game and play the sound if TRUE? Or am I completely off-track understanding what you want to do?
 Mike:
#8 posted by metlslime [204.15.3.5] on 2007/08/09 00:33:33
well, it sounds like preach's save game code would fix your problem, but I have a second problem that you don't have, which is that the sound won't play at all if you are too far away at the time it is first triggered. Your music is always audible, so there's no worry about being too far from the emitter at the time that it starts up.
 Model Import
#9 posted by Lunaran [76.208.69.54] on 2007/08/09 05:18:15
I started messing with the quake model gen source to make it parse ascii files instead of .TRI, so that I could export to text from my modeler of choice (ie maya). I got all that working fine as far as I can tell, but the .mdl that gets written out crashes Fitzquake and every model editor I've found to try. Stepping through the exporter in debug doesn't really seem to show anything wrong, as the data is all seemingly correct before it gets written.
I took a break bashing my head against this a long time ago (like the end of 2006 now that I think about it :( ), so if I started poking at it now it might become obvious to me, but does anyone have any tips or suggestions? Are there any quake ports or other bits of software that I can try to load a model in that will actually tell me what part of the file is horked rather than just pooping?
 Model Import
#10 posted by Preach [217.42.220.35] on 2007/08/09 12:59:25
A good starting place would be:
http://tfc.duke.free.fr/coding/mdl-specs-en.html
This gives you a big chunk of c code that will read a mdl file. You can skip the chunk about rendering it and just write a quick function that prints out the header data once it's loaded it, to check whether that's been written correct or not.
You might also want to look at
http://people.pwf.cam.ac.uk/~ajd70/mdl_export.py
it's an export script for blender written in python. I wish I could remember what I did to make it work though, I had the same problems as you are and spent a few hours staring at a hex editor to find out what went wrong. If anything jogs my memory I'll let you know. Shame I never got round to writing the corresponding import script, it'd probably be good for diagnosing the problem...
 Yeah
#11 posted by Lunaran [24.158.1.74] on 2007/08/09 18:12:03
I've looked over all that in the quake and modelgen sources, but I'm not very confident in writing a new piece of software to check why the last piece of software I wrote doesn't work, because clearly there's no guarantees the new one's not going to be fucked in some tiny significant way also, especially if they're both doing the same things to the same data structures. I'm just a simian level designer.
Part of the problem is that I had to do so much to get the thing to a testable state - .bmp import for the skin and then my ascii reader thing, because there's no program left on earth to write TRI files and there's no program left on earth that'll write whatever silly-ass image format modelgen looks for.
 Hmm
#12 posted by Preach [81.153.26.88] on 2007/08/09 18:35:02
Well, upload an example model that the tool exports and I'll take a look at it, try and figure out what's wrong with it.
 Okay...
#13 posted by metlslime [71.202.113.29] on 2007/08/10 07:17:30
The steam jet sound problems seem to be solved.
First, I play the looping sound whenever the object is turned on, and the "fade out" sound whenever it is turned off. This was the original naive implementation.
Second, to deal with the problem of steam jets turning on when you're far away, I re-trigger the sound every 0.1 seconds when you are between 300 and 350 units away. The clipping sound artifact is there, but since it's so quiet at that distance, you barely hear it. When you get closer, it stops re-triggering it so you can hear a perfectly looped sound.
Third, I used Preach's loadgame callback idea to retrigger all sounds in case you are standing within 300 units when you save and reload the game.
Problem solved! Thanks for the help preach.
 Oh Wow
#14 posted by Lunaran [24.158.1.74] on 2007/08/11 02:34:17
thanks Preach! It might take me a bit to gather all the code and stuff back up and actually produce one, but I'll hit that this weekend.
 Pointers Anyone?
#15 posted by Mike Woodham [81.158.239.232] on 2007/08/11 23:46:40
So I thought I would try Preach's code from above and simply put a call to my music_play_tune routine for any savegame but got this super message from aguirRe's engine.
This Onion
CDAudio: drive not ready
CL_SignonReply: 1
CL_SignonReply: 2
INDIRECT 28(self)entity 0 481(distance).distance 21507(?]
STORE_V 28(self)entity 0 4(?]
STORE_V 323(CHAN_VOICE) 2.0 7(?]
STORE_V 21505(?] 10(?]
STORE_V 21506(?] 13(?]
STORE_V 21507(?] 16(?]
CALL5 489(sound)sound()
ADDRESS 28(self)entity 0 147(use).use 21508(?]
play_music.qc : music_play_tune : statement 51
world.qc : LoadGame : statement 0
world.qc : StartFrame : statement 16
PR_ExecuteProgram: assignment to world entity
Host_Error: Program error
The idea was to play whichever tune was currently set. Clearly, I am not understanding qc here.
 In
#16 posted by aguirRe [213.101.73.100] on 2007/08/12 00:18:44
function music_play_tune in file play_music.qc, there's an entity propery ("use" I think) that you're assigning some value at statement 51.
This entity is world (= 0) at the reported occasion and this is not allowed, you may not change the world's properties.
It's probably an un-initialized entity variable that causes this issue. If I saw the corresponding QC code, it'd be easier to explain.
 Hehe
#17 posted by aguirRe [213.101.73.100] on 2007/08/12 00:21:15
Does this mean you're working on "This Onion II - The Sequel"? ;)
 AguirRe
#18 posted by Mike Woodham [81.158.239.232] on 2007/08/12 12:45:15
Does that mean I would have to intialise my music sounds in world.qc instead of calling the function play_music where they are usually precached? I can get around the "use" statement.
Oh, and according to my publicist, I have to give a "no comment" to your last question :-)
 From The
#19 posted by aguirRe [213.101.71.95] on 2007/08/12 13:18:58
debug output above, it's a
self.use = something
statement that's run when self == world which is not allowed. It's not the precaching that's at fault here.
Since the function is called from StartFrame initially, I'd assume that the world is indeed self at that point.
Music_play_tune is normally the think function for the play_music entity, you can't call that directly from another entity's (here: world) think code. The sound calls are also invalid then.
I'd guess you'll have to trigger the play_music entity's think function somehow from StartFrame.
 Thanks
#20 posted by Mike Woodham [81.158.239.232] on 2007/08/12 13:26:48
I'll play a little more with this to see if I can figure out a workaround.
 No, I Can't Figure It Out And I'm Going Round In Circles
#21 posted by Mike Woodham [81.158.239.232] on 2007/08/12 18:43:01
I thought I could set up a flag to say whether or not the music was playing at the time of the savegame (state = TRUE/FALSE). I know the piece of music playing by tracking it with a variable (cnt = 1/3/5/7, for 4 set pieces of music). I know both of these are saved in the savegame file (actually FALSE appears not to be saved), so presumably are loaded with loadgame.
But world.qc baulks at everything I try, usually with a 'types function and field not allowed'. So I cannot figure out how to either read the entitie's 'state' and 'cnt' and make use of them; or how to call the 'music_play_tune' function from world.qc.
Do you think I am trying to do the impossible or is it just that the logic is beyond me?
 This Might Not
#22 posted by aguirRe [213.101.69.144] on 2007/08/12 19:10:17
be a very good idea, but just to make the music_play_tune "callable" from StartFrame, you could assign a global entity var music_entity the value of self in play_music.
In StartFrame, you'd then just set music_entity.nextthink = time to make it execute as soon as possible. You should probably add a check for music_entity being not-world, i.e.:
if (music_entity)
music_entity.nextthink = time;
Maybe someone else can suggest a better way to actually achieve whatever you're trying to do.
 Btw
#23 posted by aguirRe [213.101.69.144] on 2007/08/12 19:13:50
savegame files don't contain vars that are 0 (= FALSE), so that might be why it's "not saved".
 I Don't Think It's Impossible
#24 posted by necros [99.244.15.189] on 2007/08/12 19:20:54
are you waiting long enough for all the entities to be spawned before you go searching for the music entity?
it should just be a matter of using a while loop to .chain through your entities until you find your music ent, checking the entity fields and then giving it a .nextthink and .think to call it's function.
music_play_tune likely has stuff with self in it, so that's why you'd need to do musicent.think = music_play_tune; instead of directly calling music_play_tune();.
or am i misunderstanding the problem?
 ?
#25 posted by necros [99.244.15.189] on 2007/08/12 19:26:34
savegame files don't contain vars that are 0 (= FALSE), so that might be why it's "not saved".
false = 0, and i'm pretty sure variables in quake are automatically initialized to 0 if they have no value, so technically, they are 'saved' whether it's actually in the save file or not.
 OK
#26 posted by Mike Woodham [81.158.239.232] on 2007/08/12 20:19:16
I didn't have a problem not seeing 'state = 0' in the savegame because I would have been looking for 'state = 1' to tell me if the music was playing at the time of the savegame.
No, my "problem" is that I cannot get a compile with any statement that uses something like 'musicent.think = music_play_tune;' in world.qc as I get an error of "Types function and field not allowed". I don't know how to copy one entity into another so that the world.qc can use it.
The reason I am having difficulty is that I am only an occaisional user of QC and don't really have enough depth of knowledge about the language or protocols in use. I get by, by reading other people's code and adapting it to my use or by plain old trial and error. But I don't think we have had music in Quake in the way in which I have implemented it, so nobody has yet written the code for me to adapt, and all my trials (Lord, soon be over) have ended in failure. Well, at least I'm consistent ;-)
If someone wants to take this on, I would have no problem passing my play-music code on. It's not a work of art but it does work.
And, "at the end of the day" I am only trying to tidy up something I have already finished.
 Didn't
#27 posted by aguirRe [213.101.69.165] on 2007/08/12 20:46:30
my suggestion work? To copy self in play_music, you just have a new global var
entity music_entity;
and assign self to it:
music_entity = self;
Then you set
music_entity.nextthink = time;
in e.g. StartFrame. You shouldn't set the think function, that's AFAIK already set in play_music.
You only make sure music_entity's think function will be run as soon as possible (you can't control exactly when, though).
 AguirRe
#28 posted by Mike Woodham [81.158.239.232] on 2007/08/12 22:54:23
No, it didn't work.
If I place the 'entity music_entity;' outside of world.qc I get a compile error "world.qc(359):error: unknown value 'music_entity'".
Line 359 is where 'music_entity.nextthink = time;' sits.
So I place it in world.qc immediately following the line, 'nosave float loadflag;'
I've added 'music_entity = self;' inside play_music, thinking that it needs to be there otherwise the new entity doesn't know who 'self' is.
Finally, 'music_entity.nextthink = time;' is in LoadGame, which is called from StartFrame.
Ah, but... I have just re-read everything and added '+ 3' to 'music_entity.nextthink = time;' and now it works. I had written a note in play_music that the sound will not play for one second - I read that somewhere but don't know why it is so.
Cool! Lookin' good!
Thanks.
Now I can get to work on checking which piece should play (or not). Watch this space!
Thanks again.
 Long Standing Bug?
#29 posted by Preach [81.153.30.11] on 2007/08/12 23:10:12
Is this, in the eyes of those present here, a bug? (and if so, one worth fixing?)
self.th_pain (attacker, take);
// nightmare mode monsters don't go into pain frames often
if (skill == 3)
self.pain_finished = time + 5;
You might expect that this piece of code makes sure that there is a minimum 5 seconds between each pain animation on nightmare, in the same way that self.pain_finished = time + 2; in the pain function puts a minimum of two seconds gap. But this isn't quite right.
You see, most pain functions only set pain_finished times once they've already concluded that pain_finished < time. Otherwise they'd constantly set pain_finished further into the future as long as the monster kept taking damage within the pain_finished period. Nightmare mode is, in effect, doing exactly that. You have to go 5 seconds without damaging the monster at all, rather than 5 seconds since you last caused it to go into pain.
So you end up with very odd behavior. If you pour nail after nail into an ogre, it'll only go into pain on the first one, but if you spread each nail 5 seconds apart, it will go into pain from every single one. Of course, the bug doesn't manifest itself that noticably, as 5 seconds is about enough time to kill any monster if you're focusing exclusively on it. Still, it might becomes more important with new high hp enemies, like in Quoth or the like. So, thoughts?
 Mike
#30 posted by aguirRe [213.101.74.142] on 2007/08/12 23:32:25
The reason you get a compile error is because of the order in progs.src file. Since world.qc is before play_music.qc, the compiler needs to know what it is before you can use it.
You can get around this kind of problem by declaring the global var in defs.qc or another file that's early in progs.src.
Or just declare the var in all files that you use it in. It'll just be one var anyway, as you can't have two global vars with the same name.
Good that it works now.
 Well
#31 posted by ijed [201.222.202.214] on 2007/08/12 23:51:39
In Quake2 the enemies never went into a pain animation in NM - they just ignored the shots, feeling no pain.
And it felt right, they are cyborgs. In Quake it is a bit strange that I can always count on a Vore (for example) yowling on the first hit, and have enough time in the animation to throw four grenades (1 to cause it to go into pain, three more to kill it) without reprisal.
Is it possible to add a randfloat value to the factor for pain - with the skill number deducting from this? (Yeah, just exhausted my coding knowledge).
What I'm suggesting is recoding the monster pain sequence, which can most likely cause alot of headaches, but I can see:
Create random Variable 1-10, deduct (skill level).
Is Variable higher than 5? If yes, play pain animation.
Which should give the engine less to think about for each particular monster currently in combat, since they're not all accumulating delays. This could be useful if, for example, the player is spraying nails into a horde of Vorelings.
It could also gives an organic feel to the enemies, making them less predictable and robotic.
 Sorta
#32 posted by Preach [81.153.30.11] on 2007/08/13 00:13:26
Some of the quake monsters already do that, for instance the pain decision code for the fiend is:
if (self.touch == Demon_JumpTouch)
return;
if (self.pain_finished > time)
return;
self.pain_finished = time + 1;
sound (self, CHAN_VOICE, "demon/dpain1.wav", 1, ATTN_NORM);
if (random()*200 > damage)
return; // didn't flinch
demon1_pain1 ();
So any hit of less that 200 damage has a chance of being ignored(apart from the sound). This tends to only be done for the tougher monsters though. I imagine that the vore always goes into pain because it's a more frail thing - although it does get a 3 second gap between attacks to compensate. The wizard gets a flinch value of 70 hp because if it does stop in pain, it's probably gonna die because the player can get a bead on it. Setting it that high gives it a good chance of ignoring nails. I don't think it's something that should be applied across the board though.
#33 posted by necros [99.244.15.189] on 2007/08/13 02:56:33
could make it take into account it's current health when determining whether to go into pain or not. then add a random time to it, and wait until that time expires to add more delay.
 Preach:
#34 posted by metlslime [71.202.113.29] on 2007/08/13 10:08:18
do you know if that "nosave" keyword is reliable? If i sit there and spam the save and load buttons, every once in a while the sound won't be playing after I load. If i then keep loading that one save file, it will be missing the sound 100% of the time. This suggests that something is wrong with that save file (like the loadflag variable is occasionally getting saved)
 Aghhhh!
#35 posted by metlslime [71.202.113.29] on 2007/08/13 10:37:15
now i'm finding that certain quakec changes are causing the level to not load, giving errors like
"couldn't spawn server maps/info_player_start.bsp"
"couldn't spawn server maps/samelevel.bsp"
almost as if strings in the progs are getting all jumbled up. Is frikgui27 a bad version to be using? Maybe it's got some bugs or something?
 Okay....
#36 posted by metlslime [71.202.113.29] on 2007/08/13 10:48:04
Anyway, i think i solved the issue; I guess i just needed to delay a bit before trying to play a sound. I guess sometimes if you try to play a sound too soon after starting a level or loading a save, the game just swallows it and you don't hear anything. I've noticed the same is true with printing messages to players in spawn functions.
As for the crazy errors in post 35, no idea what happened there but it's gone after making more changes.
 Yeah...
#37 posted by Preach [86.150.195.95] on 2007/08/13 11:53:07
I've had that string bug happen to me before, usually it goes away if you restart frikgui. Must be some kind of bug - if it keeps recurring you might want to use fteqcc instead, or mention it to frikac. I'm pretty sure that nosave is a reliable feature, although it sounds like you've fixed it anyway.
 Just To Close The Loop
#38 posted by Mike Woodham [81.158.239.232] on 2007/08/13 21:49:10
I put a flag in play_music set to true when music is playing and then read it in LoadGame. It works a treat.
Thanks.
 Loading DPM Model Files In Darkplaces
#39 posted by Zylyx [82.26.154.167] on 2007/12/10 13:35:48
Hi!
I posted thsi thread last week on the Inside3d forums, but I didn't get any replies, so I wnated to try my luck here, with you nice folks ;).
I'm having some trouble loading a DPM model for Darkplaces.
This is the code I have, minus the comments (added to weapons.qc)
//model precache (added at the beginning of the //file
precache_model("models/weapons/ak/v_ak47.dpm");
//Set the weapon up in players viewport
if ((self.weapon == IT_SHOTGUN))
{
self.currentammo = self.ammo_shells;
self.weaponmodel = "models/weapons/ak/v_ak47.dpm";
self.weaponframe = FALSE;
self.items = (self.items | IT_SHELLS);
}
When I try this out, the model doesnt show up, and the console reports "cant find <tex name> for mesh <tex name>, using default grey_checkerboard" (or something along those lines)
I'm using the the test v_ak47.dpm model that came with the dpm model viewer utility.
The model directory is as follows:
mygame/models/weapons/ak/v_ak47.pm
Inside the ak directory I have the following files (including the textures that the engine reports it cant find, in TGA file format):
-v_ak47.pdm
-10 of the TGA textures corresponding to the model
I would really appreciate if someone could tell me how to load and display DPM models in darkplaces.
Thanx again in advance!
-Zylyx
 Hmm
#40 posted by Preach [81.152.233.94] on 2007/12/10 20:09:46
I don't really know much about dpm models, but I guess the first thing to check would be that the filenames are correct. Can you give a specific example of one of the paths? If they came ready named with the example file then it's unlikely to be the problem. Also, see if a shorter path helps, like putting the model in mygame/progs. Again it sounds unlikely but it's worth a shot.
Otherwise I'm gonna have to pass you on to another forum again. The best place to ask/check out would be the nexuis forums. Nexuis uses dpm for all it's models IIRC, so checking out their source code/mod to see how to do it might help. If even that fails you might post on their forums and hopefully a coder there can help.
#41 posted by Zylyx [82.26.150.253] on 2007/12/10 22:59:25
thnx!
My model directory code is as follows (in the "mygame" directory in the Quake directory, coz that where my progs.dat file get's called from for my mod):
precache_model("models/weapons/ak/v_ak47.dpm");
and for the viewport setup:
self.weaponmodel = "models/weapons/ak/v_ak47.dpm";
I'll have a go at the Nexuiz forums, and I'll hopefully be able to get some info there.
 C++ Coding Help
#42 posted by necros [99.227.108.217] on 2008/03/30 08:14:01
i was wondering if someone could give me a hand with this...
basically, i wanted to create some kind of time system in a c++ game i'm working on. well, actually, i'm working on someone else's code, and currently, there's no sense of time at all, all timing is done by frames, which, to me anyway, seems like a Bad Thing.
ideally, i'd like to have a simple counter that starts at 0 and goes up in seconds like quake's 'time' float so that i can do things similar to self.nextthink = time + 5.2; (obviously, wouldn't be identical)
btw, i'm a c++ noob. ;)
 Necros:
#43 posted by metlslime [98.210.181.179] on 2008/03/30 11:04:43
you basically have a global time variable, and have the code update the value at the beginning of each frame. Probably, you'd do it in the main loop that runs your game. And the time you can get by using the appropriate system call, for example windows has one, SDL has its own, etc. See Sys_FloatTime() in the quake source for an example of how it's done.
Once you have a time variable that is available to any piece of code, you can do simple tests like: if (this.nextthink <= time) this.think();
 Or
#44 posted by megaman [84.63.76.38] on 2008/03/30 15:22:46
you hand the last frame time delta into all your updates
 Ioh
#45 posted by megaman [84.63.76.38] on 2008/03/30 15:24:24
and, upon reading metl's answer a bit more:
you'd also have the main game loop decide when to render a frame and when to update the gamestate (ie. seperate render() and update() methods).
 Also...
#46 posted by metlslime [98.210.181.179] on 2008/03/31 01:33:56
like megaman said, some functions (such as physics/movement) will want a "frametime" delta in addition or or instead of the global time. So you should have both be available.
 Well,
#47 posted by necros [99.227.108.217] on 2008/03/31 04:46:09
i found out that clock() returns what looks like a simple integer in msec starting at 0 when the game starts, so i'm using that.
but what is this frametime delta you are talking about? like the time between frames? cause i haven't a clue on how to calculate something like that.
i realise though, that i'll eventually need something like that. i changed the movement system to work with velocity vectors but i won't be able to accurately update positions without some way to tell how much time is taking place between frames.
 Necros:
#48 posted by metlslime [98.210.181.179] on 2008/03/31 05:48:52
"frametime" i.e. time "delta" i.e. time between frames is easily calculated: just currenttime - previoustime. It is useful for things like physics, for example:
entity.position += entity.velocity * frametime;
entity.velocity += entity.gravity * frametime;
note that the second line above is responsibly for jump height being framerate-dependant!
 My Understanding Is That Timing Is Messy Stuff
#49 posted by bear [127.255.255.255] on 2008/03/31 09:13:07
Basically there are a number of ways of getting the time and some of the timers that give you the data aren't that exact.
You should be able to find some good info in the http://www.gamedev.net forums and I think I remember seeing it discussed on the http://www.shmup-dev.com/ forums too in the past.
 Thanks :)
#50 posted by necros [99.227.108.217] on 2008/04/01 20:52:51
i think i've got it working, or at least, it seems to be.
every frame:
time_currentFrame = clock();
time_previousFrame = time_currentFrame;
time_frameDelta = (time_currentFrame - time_previousFrame) / 1000;
this gives me the fraction of time per second, and i have one function that does:
nextPosition = currentPosition + (velocity * time_frameDelta)
for all movements.
for actual velocity calculations, i capped that at 10 frames per second (every 100ms) to keep cpu usage down for needlessly precise velocities.
 Umm
#51 posted by bambuz [91.152.87.250] on 2008/04/02 02:23:49
you have to reverse the order of the first two lines?
 Yeah.
#52 posted by necros [99.227.108.217] on 2008/04/02 04:47:02
:P
 Function
#53 posted by necros [99.227.108.217] on 2008/04/04 22:11:32
how do you call a function outside of the class you're in atm? is it even possible?
i know you can do object->doThis() but that requires you to first find the pointer for that object, and then that function usually means you want to perform the function on that object...
i wanted to do the old style C thing where you just have a function you call from anywhere (like how T_Damage and T_RadiusDamage work in quakeC).
i'm kind of shit at this whole OO stuff, so am i going about this the totally wrong way?
 Make It A Static Method
#54 posted by czg [83.253.254.12] on 2008/04/04 22:25:30
#55 posted by JneeraZ [24.199.192.130] on 2008/04/04 22:29:47
Or just place the function outside of any class definitions. Functions at the global level work the same as C functions.
 How?
#56 posted by necros [99.227.108.217] on 2008/04/05 00:10:17
how exactly do i make it static? or how do i declare the function outside a class definition? do i make a new cpp file or something or..?
 Static
#57 posted by bambuz [91.152.87.250] on 2008/04/05 01:02:27
is another modifier, kinda like private or public.
A static thing is something you can not make instances of, kinda.
So you have classes like Moose and you can make moose1, moose2 etc... But there can be a static method in the Moose class that is not particular to any moose1 or moose2 instance.
Like double Moose.mass_of_the_sun() which then returns a static constant that is always the same no matter what you do with the moose instances.
Kinda like that. Damn it's been too long since I've coded.
#58 posted by JneeraZ [75.177.185.17] on 2008/04/05 12:23:49
necros
You're asking some pretty basic questions here in all honesty. Maybe reading a primer on C/C++ would be in order here.
 Yeah
#59 posted by BlackDog [58.7.102.12] on 2008/04/05 16:45:03
C++ is a painful and unforgiving language. If you dive right in, you're going to hit something hard and spiky.
I would go so far as suggesting a different language, if that's practical (pygame is pretty sweet). If it isn't, then you really need to read up on the basics.
#60 posted by JneeraZ [75.177.185.17] on 2008/04/05 17:22:05
C++ is fine and gets far more flack than it deserves.
C# is far superior however. FAR superior.
I guess it would help to know what specifically you're trying to code and for what platform.
#61 posted by BlackDog [58.7.102.12] on 2008/04/05 18:10:42
C++ does get treated unfairly - google Erik Naggum's usenet rants sometime for a hilarious example - but I wouldn't call it "fine".
I don't really want to get into a flamewar over C++'s fucked up design: I'm just going to note that there are plenty of better languages to choose from.
#62 posted by necros [99.227.108.217] on 2008/04/05 23:14:37
at the same time, i always learnt best by doing. it's more frustrating, but it sticks better.
i've tried reading some lit on c++ but they annoy the hell out of me. i'd rather they just give me the syntax for it and give me a brief overview of how to put it in the code instead of going into all the long winded crap about stuff i never remember anyway.
otoh, the more i look at this code, the more i feel it needs to be rewritten almost from scratch. there are some things in here which i don't like at all.
ie: instead of treating ships and missiles as inheriting from the same class, they are completely different classes, and neither of them can 'see' the other.
ideally, i would have liked to override the basic 'update' function of a base entity class for specific ones (ie: for missiles and ships) and then be able to call it by just iterating down one big list of entities and calling the same function.
instead, i'm trying to hack my way around it by making a static function in a new class so that i can call it from inside one class that normally can't see the other class.
also, for, apparently no reason, missiles aren't instanciated objects, but are regular structs which is also causing other problems.
i'm going back to school next week, so i'll probably ask these questions to my instructors instead and see what they think...
 Heh
#63 posted by necros [99.227.108.217] on 2008/04/05 23:15:07
the title for the above post should have read "that may be true, but"
 If This Is Your First C++ Program...
#64 posted by mwh [118.92.130.30] on 2008/04/06 10:45:31
you should entirely expect to have to throw it away and start again.
(Or your 10th or 100th, to be fair: "build one to throw away" is a long standing slogan of software engineering).
#65 posted by JneeraZ [75.177.185.17] on 2008/04/06 11:35:49
The problem is that hardly anyone ever does that. :) That's where horrible feature bloated abominations are born.
 Unarmed Ogre
#66 posted by ijed [190.20.122.225] on 2008/06/01 03:03:43
I've been stuggling to make an Ogre variant and I'm having troubles with ai/fight/ogreb.
Basically the fat cunt keeps trying to go to th_missile when he has no grenades (crash). I must be missing something obvious here but I don't know what.
The error returned is on his run sequence (has all his own functions) but if I replace his th_missile linking it to eg.melee then I'm ok, except it takes him ages to close the distance because he's swinging chainsaws about.
NULL function
Basically I don't want him to ever th_missile - but looking over ai and other monsters sheds no light - dogs / knights / fiends all use ai_run without problem.
I'm going in circles, it seems. If anyone can shed any light on this I'd appreciate it.
 C++ For C Programmers
#67 posted by inertia [24.164.67.55] on 2008/06/01 09:18:27
http://www.4p8.com/eric.brasseur/cppcen.html
I find that documents called "X For C Programmers" tend to hit the spot. This is mainly for necros.
 Ijed
#68 posted by Supa [70.226.31.207] on 2008/06/01 11:14:34
OgreCheckAttack sets their attack state to AS_MISSILE, which leads to ai_run calling ai_run_missile, which leads to self.th_missile.. which leads to the crash.
You'll need to comment out the monster_ogre/OgreCheckAttack lines in CheckAnyAttack (so they'll use CheckAttack instead) and make sure you don't give them a .th_missile, else CheckAttack will convienently call self.th_missile for you. :)
 An Ogre By Another Name
#69 posted by Preach [131.111.213.35] on 2008/06/01 11:39:17
Have you tried changing the classname from monster_ogre to, for example, monster_ogre_unarmed? I have a feeling that might make it work.
The reason why is hidden in fight.qc and ai.qc. fight.qc is the place to start, have a look at the two functions CheckAttack and OgreCheckAttack. The former is the generic function for any monster, and it's careful enough to check whether self.th_missile is set or not before deciding to make a missile attack. OgreCheckAttack is more presumptive, it knows that an ogre has a missile attack and so goes straight ahead with setting AS_MISSILE.
This is all quite deceptive, as OgreCheckAttack never explicitly uses th_missile - it just sets AS_MISSILE and lets ai.qc do the th_missile part. ai.qc is also the place to find out how the game chooses between CheckAttack and OgreCheckAttack. The function that decides is called CheckAnyAttack, and as you can see it decides based on the classname. So if you give your melee ogres a different classname then it should use CheckAttack only, which is safe to use without th_missile set.
The downside to this method is that, like with monster_ogre_marksman, your ogres will be able to infight with each other. So you could just make the check in CheckAnyAttack more stringent:
if (self.classname == "monster_ogre" && self.th_missile)
return OgreCheckAttack ();
For neatness of code, this way is probably better, as it means you can have a single spawnfunction for both grenadiers and berserkers. This is good code sharing, as any change you make to an ogre you probably want to make for both of them.
The third solution would be to modify OgreCheckAttack to properly check for th_missile, but I don't think that's the best way to go, it could end up complicated.
 Infighting
#70 posted by rj [86.1.160.132] on 2008/06/01 15:10:32
it's pretty easy to get around the infighting problem above when setting up a new classname. you just need to set up 'classes' (a la quoth) and modify the infighting code slightly
here's how i did it..
- add .string class; to the monster ai in defs.qc
- add self.class = "ogre"; to the different ogre classnames
- then in combat.qc under the '//react to damage' part, change this line:
if ( (self.flags & FL_MONSTER) && attacker != world)
to read this:
if ( (self.flags & FL_MONSTER) && (self.class != attacker.class) && attacker != world)
i think that was it. you can use it to group allied monster types or groups, either in the qc or simply by adding 'class' to any other monster entity (say if you had one particular battle where you wanted the monsters to focus on the player only)
 Excellent
#71 posted by ijed [190.20.65.61] on 2008/06/01 18:16:41
Thanks for all the answers, I should be able to close this issue sometime today.
I wanted to maintain the original ogres so made the new one a different classname - ogreb (berserk) already.
As to infighting, I'm thinking of modifying all Ogres to act the same as grunts. This might sound like a cheap dodge to not have to fix the issue, but I never did see the Ogres as particularly polite, and I'm a fan of chaos.
Thanks again.
 Argh
#72 posted by ijed [190.20.65.61] on 2008/06/01 18:24:37
Solved!
Turns out I was calling ogrecheckattack for the new ogres inside ai.
You live and learn.
 Monster Won't Get Killed
#73 posted by madfox [84.26.60.178] on 2008/09/09 00:06:00
While coding for a new Q1 monster I made up a little qc where I placed all args like stand walk run etc.
Having the monster standing in game all looks well, untill I try to kill the moster.
Having two monsters in game there's always one that don't die.(?!)
I hear the kill sound but the monster just goes on turning into stone to my bullits.
I have the regular death subroutine.
http://members.home.nl/gimli/Imp.qc
#74 posted by necros [99.227.108.217] on 2008/09/09 00:27:45
lol...
if (random() < 0.5)
imp_die1 ();
these lines mean if random() (random number between 0 and 1) is smaller than 0.5, then it will play the animation sequence.
so half the time it will play the animation and half the time it won't.
 Well
#75 posted by madfox [84.26.60.178] on 2008/09/09 00:44:57
cll me a fool, but what should I number 0.5?
 Right
#76 posted by madfox [84.26.60.178] on 2008/09/09 00:52:05
if(me a fool)half the time < I ain't).
thanks for pointing me out.
 Impulse Command Queuing.
#77 posted by necros [99.227.108.217] on 2008/09/20 23:17:10
impulse command queuing.
is that handled by the engine?
in ImpulseCommands there's the if statement:
if (self.attack_finished > time)
{
self.impulse = 0;
return;
}
which seems to me to mean "if attack_finished is still ticking down, do not accept ANY impulses (set to 0) and then break out of the function altogether.
yet, when you attack with say the rocket launcher and then press 8, the impulse 8 command seems to get queued up and is executed after attack_finished is done.
is there something going on behind the scenes here? i'm actually trying to stop the queuing from happening, but can't really see even where it's happening.
 Hmm
#78 posted by Preach [86.146.19.8] on 2008/09/21 00:05:45
I don't see that line in the version posted at
http://www.inside3d.com/browse.php?show=weapons.qc
I'd probably say the place to look is in W_WeaponFrame, where any call to ImpulseCommands is skipped if self.attack_finished > time. If you really wanted to block impulses, then putting self.impulse = 0 just before that return should do the trick.
 Hm...
#79 posted by necros [99.227.108.217] on 2008/09/21 05:41:57
that's really odd. that means the if check in ImpulseCommands is completely redundant. it will never get to that point because an identical if check is done prior to even getting in that function. o.0
 Random Coding Oddities In Quake?
#80 posted by mwh [118.93.20.2] on 2008/09/21 09:40:41
Surely not!!
 Yeah, But
#81 posted by Preach [81.153.85.157] on 2008/09/21 11:39:38
Yeah, but that if() check isn't actually in the standard quake source code for ImpulseCommands, I don't know where you got it from : -p
 Fire And Switch?
#82 posted by Lardarse [62.31.165.111] on 2008/09/21 19:52:00
If you want to stop the queueing, then putting that the return in the if() in W_WeaponFrame would do it. If however, you want some impulses to always happen, then you need to put a separate check in, to happen before that check.
Of course, an even more intricate fix (which goes in the other direction from where you want to go) is to track what the impulses would make the weapon change to if you were not firing (setting .weapon appropriately, so the hud light shows what you will use next), and then switch to it when the player has stopped firing. Of course, there is another issue again, in that I don't think you can switch away while firing a nailgun, because the way they fire is handled differently is handled to other weapons.
 I Sorted It Out
#83 posted by necros [99.227.108.217] on 2008/09/21 19:56:38
i just moved the self.impulse = 0 to the end of W_WeaponFrame and removed the if check with the return. i have no idea where the if check in ImpulseCommands came from but i took it out as well and it works fine after re-arranging the way firing and impulsecommands was handled.
 And I Forgot To Mention A Couple Of Things
#84 posted by Lardarse [62.31.165.111] on 2008/09/21 20:00:06
You should probably use else if in ImpusleCommands(), so that it can go faster, May not make that much difference these days, but it's probably a good idea to anyway.
Even more of a timesaver, though, is skipping all of the impulse checks completely if self.impulse is 0. I don't actually know when impulse gets truncated to the lower 8 bits, but I think it's before the QC sees it (and possibly it only gets sent over the network as a byte), so you don't have to check for it being anything else that resolves to 0.
 Profile
#85 posted by Preach [81.153.85.157] on 2008/09/21 23:59:23
There's a built in way to check how fast qc runs on an engine, in case you're optimising things. The command is "profile", and it lists the top 10 functions in terms of commands executed since the last profile command or server start. As an example on unpatched quake:
e1m6 at 72fps
425616 PlayerPreThink
270814 WaterMove
241542 PlayerPostThink
202689 ImpulseCommands
177480 CheckRules
165648 CheckPowerups
125843 ai_stand
94928 StartFrame
76144 door_touch
Things worth noticing:
*ImpulseCommands is certainly up there. Almost certainly the most important optimisation would be to skip everything if self.impulse is 0. I'd agree with doing that check before calling the function ImpulseCommands(calling functions costs a few operations).
Further optimisations would be the else if Lardarse suggests, and storing self.impulse in a local float at the start of the ImpulseCommands function - to avoid looking it up each time, which is more expensive if you have to go through a layer of self.something first. But optimising the very rare cases where there is a change of weapon isn't gonna yield anything like the benefit of skipping the whole thing in 99.9% of frames.
* CheckRules places highly, even though that function is entirely pointless in single player games. I think the calls to cvar are pretty expensive here.
* Results from this kind of assessment will be different at different framerates. The playerprethink type functions occur every frame, but since monsters think in 0.1 second slices, that's only 1 in 7 frames. Playing at 15fps, I'd imagine ai_stand could top the charts.
 Boy
#86 posted by Lunaran [97.87.13.222] on 2008/09/22 03:25:26
I've learned that if you create a new monster with a new model, the $frames still have to be named in the progs.dat urnewmonster.qc file in the same order they're in the .mdl.
I assume the compiler converts frame names to integer offsets and the names of the frames themselves are irrelevant?
#87 posted by necros [99.227.108.217] on 2008/09/22 03:41:44
I assume the compiler converts frame names to integer offsets and the names of the frames themselves are irrelevant?
yup.
 And
#88 posted by ijed [216.241.20.2] on 2008/09/22 15:33:34
Is it relevant in any way how many frames there are per line? I've had no problems, but then again I haven't experimented much ie. tried to break it.
Is there anything stopping me from having, say, 20 frames on the same line in the .qc?
 I Went Up To 18 With Frikqcc
#89 posted by Lunaran [24.158.1.74] on 2008/09/22 16:34:06
and it didn't seem to mind
 Schnurps
#90 posted by Kinn [86.153.225.202] on 2008/09/22 21:44:44
whenever i coded new monsters, i just looked up the frame number in QME and just typed the number, rather than having to list all the $frame bollox at the top of the file
 Well
#91 posted by Lunaran [97.87.13.222] on 2008/09/23 01:31:31
isn't that arguably more confusing? if I reexport the model with new anims in it it's kind of nice to just be able to insert them in the list at the top than have to replace all of the numbers in all of the frame functions ...
 I Grudgingly Agree
#92 posted by ijed [190.20.69.159] on 2008/09/23 05:58:25
If you're thinking about an end user for the code that's a nightmare. Also depends on having the anims in one seqeunce rather than seperated.
It's interesting hacking up all this stuff.
 Profile Is Going In The Reference Book
#93 posted by Lardarse [62.31.165.111] on 2008/09/23 09:13:01
and storing self.impulse in a local float at the start of the ImpulseCommands function
Probably not worth it. Except maybe for RuneQuake, or anything else that has impulse overloading...
The frame macros can be called anything you like. It's usual, though, to call them something similar to the model, as it makes using them easier. And as how how many you can fit on one line, I think your most sensible limit is the right edge of your text editor...
 Temporaries
#94 posted by Preach [217.44.87.165] on 2008/09/23 10:39:19
Yeah, I agree it's not useful in ImpulseCommands once you have the other improvements. But once you sort out the needlessly expensive functions like that, you start to notice that functions like visible() and range() begin to show up in profile. And in those, you do get (theoretical) performance improvements by using locals. This is my current optimised range function
float(entity targ) range =
{
local vector spot1;
local float r;
spot1 = self.origin + self.view_ofs - targ.origin - targ.view_ofs;
//PREACH: this only uses two temps
r = spot1 * spot1;
//
//PREACH: kept in a local since we use it twice
//PREACH: it would still be stored in a temp local float
//PREACH: but would re-evaluate each time in case spot1 had changed. We know it can't, so we save the result.
if (r < 500 * 500)
{
if (r < 120 * 120)
return RANGE_MELEE;
else
return RANGE_NEAR;
//PREACH: nesting the ifs like this takes at most 2 comparisons, down from 4 in the original
}
else
{
if (r < 1000 * 1000)
return RANGE_MID;
return RANGE_FAR;
}
}
Skips the expensive calls to vlen, and nests the ifs for a slightly shorter path to RANGE_MID or RANGE_FAR. Note that in frikqcc and fteqcc with the flatten constants optimisation on, 120 * 120 and the others are evaluated at compile time. If you're not using that optimisation, then you should work out those values ahead of time. I leave them like that to make clear where the magic numbers come from.
You can get a little more juice out of visible if you use
float (entity targ) visible =
{
traceline (self.origin + self.view_ofs, targ.origin + targ.view_ofs, TRUE, self); // see through other monsters
if (trace_inwater)
{
if (trace_inopen)
return FALSE; // sight line crossed contents
}
if (trace_fraction == 1)
return TRUE;
return FALSE;
};
In FTE, putting the arguments straight into the traceline function call is actually faster than not doing so. I also put the trace_inwater check first, as I figure that's more likely to fail most of the time, so you don't need to bother checking trace_inopen(which under the same assumptions is usually likely to succeed). Doing && in an if statement always evaluates both statements in qc, so nesting ifs can make faster executing code where it matters.
 So Why Not Just
#95 posted by Lardarse [62.31.165.111] on 2008/09/23 12:01:25
make the profile command show more than 10?
And of course, format things so they make sense to whoever is writing the code; for me this means not putting things on multiple lines for the hell of it :-)
 Also Visible
#96 posted by Lardarse [62.31.165.111] on 2008/09/23 12:04:56
Isn't this the function that you suggested changing in another thread (can't find it) to make monsters see you while in water?
 Suggested Is A Strong Word :-P
#97 posted by Preach [217.44.87.165] on 2008/09/23 12:15:23
I wouldn't say the water vision change was something that should always be changed, someone was asking how it could be done, so I posted it. Really it's a circumstantial choice, if it causes problems in a specific map then visible is the place to change things, but in general keeping water opaque is a good idea for fish if nobody else.
 Ok, Then... "mentioned"
#98 posted by Lardarse [62.31.165.111] on 2008/09/23 15:58:43
Selective based on monster type, though.
 Gnurps
#99 posted by Kinn [86.153.225.202] on 2008/09/24 22:35:12
isn't that arguably more confusing?
hehe, well I admitted it for the comedy value really; I'm aware that it is an atrocious way of coding monsters :)
 NULL
#100 posted by JneeraZ [75.177.185.17] on 2008/09/26 12:38:01
Did I ask this before? I don't remember, honestly.
Anyway, is there a concept of a NULL value in QuakeC? Like say I want to define a local entity variable and set it to NULL before doing some other processing and at the end do a check like:
if( myEntity == NULL) or if( !myEntity )
Is that possible? I think I'm missing something obvious because I can't get the compiler to accept null, Null, NULL or 0 (zero).
Help?
 Pointer To World
#101 posted by Lardarse [62.31.165.111] on 2008/09/26 13:50:17
Most things tend to use world as the "NULL pointer". find() and variants usually return world if nothing is found, or end a linked list with world. I believe traceline() sets the hit entity to world if nothing is hit (the general way to detect no hit is if(trace_fraction == 1) although sometimes testing for hitting world is acceptable).
Usually, world is entity 0 (maybe eprint() might be able to tell you), although the compiler probably doesn't accept the implicit cast from float to entity.
Other NULL values are 0, "", and '0 0 0'.
 Yeah
#102 posted by Preach [86.148.9.7] on 2008/09/26 14:18:22
Just to add that
if( !myEntity )
is valid qc and equivalent to
if(myEntity == world)
If world can be a valid return type you need to deal with that as a seperate case somehow.
#103 posted by JneeraZ [75.177.185.17] on 2008/09/26 14:29:04
Ahh alright. Thanks!
 Removing Entities And It's Effects On Other Things
#104 posted by necros [99.227.108.217] on 2008/10/05 23:00:36
so, say i have ent1.owner = ent2
and ent2 is removed. what happens to my pointer on ent1.owner? is it set to world or is it now corrupted junk?
can i do a check if (!ent1.owner) now and it'll pass?
 No
#105 posted by Preach [81.153.28.98] on 2008/10/05 23:41:48
The entity field continues to point to the same "slot" that the original entity occupied. Worse, after two seconds that entity slot can be reallocated when a new spawn() request is received, so the field now points to a valid entity, but an entirely unrelated one.
It's also worth noting that most of the fields on the removed entity will still be readable, and contain the same values they did before the entity was removed. The engine resets a few fields on removal, like solid, model and origin, but doesn't zero all of them until it's reused by the spawn() command. You can observe a side effect in fitzquake if you turn r_showbboxes on; a removed entity creates a bbox of that entity's size at the origin.
You could exploit the above fact to write code which can tell if an entity is removed or not:
Before removing an entity, set a float .isremoved on that entity to TRUE. The value can still be read, and will be reset when the entity is respawned as something else. You have to pinkie-swear never to modify that value outside the remove() function for it to be reliable.
I wouldn't recommend actually doing that though, because it's kinda relying on "undefined" behaviour in the engine - that removed entities can still be read. Engines which had more advanced entity management might not enforce that.
It's probably better to have a destructor function for the entity which is being removed which knows which entities will refer to it and sets them to WORLD. This would be practical if it's a master-slave kind of thing, not so much if you're worried about a monster getting removed and other monsters suddenly having an invalid .enemy...
#106 posted by JneeraZ [75.177.185.17] on 2008/10/05 23:45:03
"You can observe a side effect in fitzquake if you turn r_showbboxes on; a removed entity creates a bbox of that entity's size at the origin. "
Hahaha, so THAT'S what that is. I wondered what that box at the origin of the world was. Thanks! I thought my code was doing something wacky...
 Jesus
#107 posted by necros [99.227.108.217] on 2008/10/06 01:03:51
9_9
 Mind Melting Code
#108 posted by Preach [81.153.24.252] on 2008/10/09 15:54:07
Ok, I dug out the monster I wrote a few months back, here's some code which actually tracks all of your removed entities in a linked list. The file is pretty thoroughly commented, with a big block of text at the start describing how you might use it, and how to integrate it into a standard qc source.
http://www.btinternet.com/~chapterhonour/chaintrack.qc
The main application is a new field on entities you can read called .reused. Positive/zero values of .reused mean the entity is currently spawned, negative values mean it's currently removed. The absolute value of .reused gives you the number of times the entity has been removed previously. This gives you an index you can compare to see if a stored entity differs in number of removals from the value it used to have - i.e. it has been removed and restored.
I've tested it with fitz, bjp and dp, and it seems to function correctly in all 3. If anyone wants to know how it works, I can post that up too...
 Custents
#109 posted by madfox [84.26.60.178] on 2008/10/10 08:07:10
I was trying to add some doombirds to my map, and couldn't find the right movement for the thing. If I use a func_train it worked, only the sight of a plane flying backwards is a little queer.
So I took the custents and saw the map with the falling wall. It has a four way movement train that uses func_rotate. I integrated the doombird in it and it worked out fine again.
One thing I can't get is
why can I jump on the func_train in custents,
and why do I drop through it in my own version?
 I'm Guessing
#110 posted by necros [99.227.108.217] on 2008/10/10 09:23:20
you mean func_rotate_train and not func_train?
in which case, you need the oft-posted czg rotation tutorial which, ironicall, i don't have the link to. :P
 Append
#111 posted by necros [99.227.108.217] on 2008/10/10 09:24:17
that's to say, the tutorial explains how to get collision on your rotaters. it's kind of wierd and annoying.
 Thanks
#112 posted by madfox [84.26.60.178] on 2008/10/10 10:00:53
necros, the turning goes al right.
it is just that funny behaviour that when I play the map falendoor of custents I can stand on the func_train and I rotate in eyesight.
when I transponse the map coordinates of that func_rotate_train to my own the train isn't solid anymore. (?!)
 Oops
#113 posted by madfox [84.26.60.178] on 2008/10/10 21:18:46
forgot to include func_movewall. Now it's solid.
There's an odd point where the func_rotate suddenly behaves like a counter-turn in the opposite. Can't fly the thing without Doom patents.
 Just
#114 posted by ijed [216.241.20.2] on 2008/10/10 22:27:29
To throw a spanner in the works -
Would it be possible to have the plane as a model, with all it's takeoff animation (turning etc.) done in Qme?
Or would the size of the animation break the model - look in the wrong direction and the game assumes you can't see it because it's in a different visleaf.
 There's Something Worse That What You Mentioned
#115 posted by necros [99.227.108.217] on 2008/10/10 22:40:10
about doing it that way.
the way that vertex coordinate info is stored is completely relative.
this means that no matter how big or small your model is, the only thing important is how far from the origin all the vertices are.
this has an impact on the resolution of the model.
in quake, you could make a miniscule model of a bolt and it'll look completely fine.
but if you made a huge wall with the same bolt in the middle, the bolt would be messed up.
this is because the huge wall caused the scale of the vertex 'snap' to be larger.
if you made a plane model that was fully animated to fly around in, say an area of 1024x1024, your plane's vertices would probably be so low resolution as to not even be able to make out what it was.
as an example, look at the amount of vertex dancing on the vermis model. compare it to something like the fish model (which hardly moves) to get a good idea of how it impacts vertex position.
 Another Way To Look At It.
#116 posted by necros [99.227.108.217] on 2008/10/10 22:42:33
imagine that a vertex in a model can only be on a grid of 256x256 units. it can rest on any even number from 0 to 255.
but that this grid can be stretched in all directions.
so if your model was 1024 units tall, it's vertices could, internally, only snap to a 256 tall grid.
that is to say that in the game world, the model's vertices would fit on every 4 grid units, instead of every 1.
#117 posted by JneeraZ [75.177.185.17] on 2008/10/11 01:25:55
Ahh right. I was going to call you out on that resolution thing but then I remembered Carmack's 256x256x256 cube compression stuff. Yes, quite the ugly issue.
 Ijed
#118 posted by madfox [84.26.60.178] on 2008/10/11 03:21:41
this is aa far as I have come with the the doombird and custents.
Coding a mechtech is somewhat harder, but would be better.
http://members.home.nl/gimli/dbird.dz
 Ha!
#119 posted by ijed [190.20.93.238] on 2008/10/11 15:06:11
That's pretty fun. The collision seems to go a bit nuts and just do its own thing, but even so.
Maybe some Qc to add grenade style smoke to the jets?
 As To The Model Thing
#120 posted by ijed [190.20.115.33] on 2008/10/11 19:01:42
So to do it with a model would require a func_modeltrain of some sort then, so it wouldn't just dissolve into a mess.
That explains why all the monsters seem to have Parkinsons in their idle animations though.
#121 posted by JneeraZ [75.177.185.17] on 2008/10/11 20:15:10
The larger ones anyway. The Shambler has way more error in his verts than, say, a soldier. The rest of the jittering comes from the fact that, I believe, Quake only supports integer locations for vertices.
 I'm
#122 posted by ijed [190.20.72.178] on 2008/10/11 20:37:40
Used to engine side vertex interpolation so don't usually notice it so much, except when looking at the models in raw state, as it were.
 Swung
#123 posted by madfox [84.26.60.178] on 2008/10/11 21:27:50
custents support the func_rotation and the func_rotate_train.
I'm trying to understand these options to get a better flyer.
that strange swing don't seem related to the func triggers.
Haven't found out where it comes from.
Reason that in custents a part of the func_rotate is hided.
 Armor
#124 posted by madfox [84.26.60.178] on 2008/10/14 10:35:53
I succeeded to create a health bowl and give it a health strength , by adding a health function in the qc.
I thought giving it armor points would be that easy. But it isn't.
There are only three IT_ARMOR types.
By substituring one I get my extra powerup object of ten armor points.
But not as alike the health paks I can only take one at the time,
the rest stays non solid as if I have taken a full armor .
 To Clarify
#125 posted by Preach [86.153.44.107] on 2008/10/14 12:49:50
I want to check what you're trying to do here. You would like an item which gives a boost of, 10 points of armour to a player who picks it up. So far, you've managed to make an item which gives the player 10 points of armour if they pick one up, but then subsequent ones will only top the player back up to 10, and if they are already at 10, then it doesn't increase.
To me, that sounds exactly like what would happen if you rewrote the green armour to have 10 armour points rather that 100. Have I read your aim and current result right?
 Yes
#126 posted by madfox [84.26.60.178] on 2008/10/14 12:59:29
I trie to reproduce the armor powerup with skulls, like in Doom
 Items
#127 posted by madfox [84.26.60.178] on 2008/10/14 13:05:41
I was rewriting in the items.qc
+---------------------------------------------+
void() armor_touch =
{
local float type, value, bit;
if (other.health <= 0)
return;
if (other.classname != "player")
return;
if (self.classname == "item_armor1")
{
type = 0.3;
value = 100;
bit = IT_ARMOR1;
}
if (self.classname == "item_armor2")
{
type = 0.6;
value = 150;
bit = IT_ARMOR2;
}
if (self.classname == "item_armorInv")
{
type = 0.8;
value = 200;
bit = IT_ARMOR3;
}
if (self.classname == "item_skull")
{
type = 0.1;
value = 10;
bit = IT_ARMOR1;
}
if (other.armortype*other.armorvalue >= type*value)
return;
+-------------------------------------------+
};
void() item_skull =
{
self.touch = armor_touch;
precache_model ("maps/skull.bsp");
setmodel (self, "maps/skull.bsp");
self.skin = 0;
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
+---------------------------------------------+
 It's The Last 2 Lines
#128 posted by Lunaran [97.87.13.222] on 2008/10/14 15:35:18
they skip the pickup entirely if the armor you're touching is weaker than what you have. you need to add a special exception there for skulls that add 10 armor and keep the preexisting armortype.
 Additionally
#129 posted by Lardarse [62.31.165.111] on 2008/10/14 15:52:25
You should check for the player having no armor, and if this is the case, set their armortype to green (0.3 and IT_ARMOR1)
You may also want to set a limit for both health and armor shards. Probably at 250 or soemthing like that. I don;t know if the 3 numbers at the bottom are limited to 8 bits, but even if they're not, you might want to not let them get out of hand...
 Addition
#130 posted by Preach [86.153.44.107] on 2008/10/14 17:54:08
There's another problem with this code, which is the way armour and health packs differ in increasing stats. A health pack adds on a certain amount of health to the amount you started with. Armour always sets the value to the same amount, regardless of how much you had, it's not adding anything on. Code like "add on 150 points to his armour, but then if the total is more than 150, cap it there" would be redundant.
So you're going to have to write something more complicated.
 This
#131 posted by ijed [216.241.20.2] on 2008/10/14 19:41:56
http://qexpo.tastyspleen.net/booth.php?id=131&page=273
Might help some, it's Dr Shadowborg's revised health system tutorial.
 Thanks For Your Explain
#132 posted by madfox [84.26.60.178] on 2008/10/14 23:46:40
I'm no coder, so the fact I get any outcome is a wonder to me.
With health it was easy, adding a new b_model with args and the code run.
With this armor code I can let the strength deplenish untill it reaches under 10 before it powers up.
But I can change to any value, only 10 counts.
Eventually I can understand the options you mention,
but I miss the ability to write them down.
 Adding New Weapons
#133 posted by Killa [70.126.212.240] on 2008/10/15 10:54:58
hey, was wanting to know if you guys knew of a good and easily understood tutorial for adding a new weapon, that also shows me how to add it to where its usable when added to a FGD "not just when you have a shot gun and enough ammo -.-)
 Ok, More Detailed Explanation
#134 posted by Preach [86.150.194.206] on 2008/10/15 11:07:41
I think the best way to do it would be to write an entirely separate touch function for your new item. It needs to:
* Do the usual checks that the other entity is a player who is not dead.
* Deal with the 4 cases: player has red/yellow/green/no armour.
* Add the correct amount to the armour total.
I'd do something like this:
void() armorboost_touch =
{
local float maxarmor;
if (other.health <= 0)
return;
if (other.classname != "player")
return; //usual checks
if(other.items & IT_ARMOR3) //Player has red armor
maxarmor = 200;
else if (other.items & IT_ARMOR2) //Yellow
maxarmor = 150;
else //deal with green and none at same time
{
other.armortype = 0.3;
other.items = other.items | IT_ARMOR1;
maxarmor = 100;
}
other.armorvalue = other.armorvalue + 10; //add it on
if(other.armorvalue > maxarmor)//if we're over max
other.armorvalue = maxarmor;//set to max
self.solid = SOLID_NOT;
self.model = string_null;
if (deathmatch == 1)
self.nextthink = time + 20;
self.think = SUB_regen;
sprint(other, "You got armor\n");
sound(other, CHAN_ITEM, "items/armor1.wav", 1, ATTN_NORM);
stuffcmd (other, "bf\n");
activator = other;
SUB_UseTargets();//fire all targets/killtargets
};
I've not tested it in game, but it should work well enough. Remember to change the line in item_skull to
self.touch = armorboost_touch;
 Hey
#135 posted by madfox [84.26.60.178] on 2008/10/15 12:07:39
that's another qup of tea Preach.
I already reminded myself to be glad with a strike of luck and leave it that way.
And yes indeed, the powerups go clearly from 0 to 100. Never thought it was possible.
Thanks!
 LIT File Format?
#136 posted by JneeraZ [75.177.185.17] on 2008/10/23 13:44:21
Can someone point me towards what the LIT file format looks like? I've spent 20 minutes Googling with nothing to show for it. Is it documented somewhere?
#137 posted by Spirit [213.39.156.179] on 2008/10/23 16:21:47
According to QIP LordHavoc created the format so just try getting hold of him in #darkplaces on Anynet (IRC). Otherwise you could read through the TomLite or Tyrlite sources (Hmap probably too), you seem to be able to grasp code (unlike me).
 I Emailed Him A Couple Of Weeks Ago...
#138 posted by RickyT33 [86.139.126.162] on 2008/10/23 16:57:59
He helped me out! :-)
 Willem
#139 posted by Lardarse [62.31.165.111] on 2008/10/23 17:05:45
From dpextensions.qc:
//DP_LITSUPPORT
//idea: LordHavoc
//darkplaces implementation: LordHavoc
//description:
//indicates this engine loads .lit files for any quake1 format .bsp files it loads to enhance maps with colored lighting.
//implementation description: these files begin with the header QLIT followed by version number 1 (as little endian 32bit), the rest of the file is a replacement lightmaps lump, except being 3x as large as the lightmaps lump of the map it matches up with (and yes the between-lightmap padding is expanded 3x to keep this consistent), so the lightmap offset in each surface is simply multiplied by 3 during loading to properly index the lit data, and the lit file is loaded instead of the lightmap lump, other renderer changes are needed to display these of course... see the litsupport.zip sample code (almost a tutorial) at http://icculus.org/twilight/darkplaces for more information.
#140 posted by JneeraZ [24.199.192.130] on 2008/10/23 17:21:47
Excellent! Thanks, that should give me what I need...
 Coding Tip Of The Day
#141 posted by Preach [81.152.235.254] on 2008/12/03 01:15:00
Don't expect them daily though, this is just my aggravation of the moment:
if(1)
dprint("1: went down the TRUE branch\n");
else
dprint("1: went down the FALSE branch\n");
This will, as you would expect, go down the TRUE branch. The value in the if() is non-zero, which is true in boolean logic.
if('1 0 0')
dprint("2: went down the TRUE branch\n");
else
dprint("2: went down the FALSE branch\n");
This will also go down the TRUE branch, it looks like any non zero vector counts as true.
if('0 1 0')
dprint("3: went down the TRUE branch\n");
else
dprint("3: went down the FALSE branch\n");
This will go down the FALSE branch! QC only checks the first component of a vector when evaluating boolean logic on them. This is a bit of an oversight, and you should be careful. If you want to properly check if a vector is non-zero, you must do it explicitly as
if(self.angles != '0 0 0')
OK, that's the one that bugged me for tonight, venting over. But while I'm posting about QC and if() logic, here's another related bug that can catch people out:
self.noise = "";
if(self.noise)
dprint("4: went down the TRUE branch\n");
else
dprint("4: went down the FALSE branch\n");
This one goes down the TRUE branch. Why it does is a bit technical, it's because if(self.noise) is checking whether the pointer which self.noise stores is non-zero. The string constant "" is not the same thing as a null pointer, it is a string comprised solely of a null terminator, which actually gets allocated somewhere and so the pointer has a non-zero value.
There are two ways around this. One is to properly null the string pointer, like this:
self.noise = string_null;
if(self.noise)
dprint("5: went down the TRUE branch\n");
else
dprint("5: went down the FALSE branch\n");
This one evaluates to false.
Alternatively you can put
if(self.noise != "")
This will go down the false branch in either of the cases self.noise = ""; or self.noise = string_null.
#142 posted by JneeraZ [75.177.185.17] on 2008/12/03 01:45:54
"This will go down the FALSE branch! QC only checks the first component of a vector when evaluating boolean logic on them."
I'd venture a guess that when it sees a string maybe it's just doing an atoi call on it, which would stop at the first space? I dunno.
 Assembling A Vector
#143 posted by Preach [81.152.235.254] on 2008/12/03 11:00:49
Looking at the assembler output, it looks like every time a vector is passed as a parameter to something, the instruction looks like:
STOREP_V VEC_ORIGIN_x, temp_0;
So it seems to be passing just the first component of the vector. What happens then is that the engine knows that this is a vector, and that the other two components will be in the next two entries in memory. Any operation with _V on the end does this.
The problem arises when you get to the IF operations. There isn't a separate case for vector, or indeed for any types. Every memory location which gets passed by the assembler to IF is cast to int, and then checked to see if it's non-zero.
It wouldn't be easy to fix this on the engine side, because you'd need to read what type of temporary was being stored, so that you could distinguish between
if(self.angles)
and
if(self.angles_x)
because the IF operation would look the same. You'd need to look back a few operations at least, which is basically a no-go.
On the other hand, it wouldn't be hard to write a compiler which always substitutes
if(vector != '0 0 0') for if(vector).
FTEQCC already offers a similar fix for
if(string)
It isn't on by default, because some of the engine extensions which add string concatenation etc. require actual tests for null strings instead of empty ones.
 Mdl Versus Sprite
#144 posted by madfox [84.26.168.11] on 2008/12/14 12:38:08
Well, I managed to get a sprite in Quake, but I was wondering how to add it to a monster's subroutine.
Simple fact, quake sprites are mostly just one model frame. Except for the orgue which is the only one with his grenade. If I'm looking to the qc I can't find nothing about sprites, so I consume it is engine wise.
When I change the model laser.mdl of the enforcer with a sprite I see only the first frame.
How do I add a sprite to a monster's subroutine?
Is it something you add to the statement of the laser.mdl of the enforcer?
 In Hope To Help
#145 posted by meTch [69.183.41.240] on 2008/12/14 17:15:32
void() s_explode1 = [0, s_explode2] {};
void() s_explode2 = [1, s_explode3] {};
void() s_explode3 = [2, s_explode4] {};
void() s_explode4 = [3, s_explode5] {};
void() s_explode5 = [4, s_explode6] {};
void() s_explode6 = [5, SUB_Remove] {};
void() BecomeExplosion =
i think you have to make a multi-image sprite, like the explosion?
and deal it out above like so, and give it setmodel "ursprite.spr"
or umm, heh <8*
 Well
#146 posted by madfox [84.26.168.11] on 2008/12/17 01:16:23
For creating a sprite it could work, but not when I try to make it happen in a monster's subroutine like the enforcer.
If I add something at the qc point launchlaser, I first need to declare the sprite frames. And as the enforcer already has it frames declared qc matches out.
 Madfox
#147 posted by necros [99.227.108.217] on 2008/12/17 01:54:27
If I add something at the qc point launchlaser, I first need to declare the sprite frames.
no, you do not. like i said before, just put a number where the $frame macro would be.
 Is It Still Necessary To Use Quakeworld Progs?
#148 posted by necros [99.227.108.217] on 2008/12/22 20:49:09
are there qw clients that can just read the normal netquake progs?
#149 posted by Spirit [213.39.186.184] on 2008/12/23 10:22:11
zQuake can do, both as client and server (so you can serve a "netquake" progs with zquake and have other qw clients connect to it).
FTE can do too.
ezQuake I am not sure, from what I know the singleplayer is broken.
 Zquake Sounds Promising
#150 posted by necros [99.227.108.217] on 2008/12/23 20:07:13
except i have the same problem i have with a lot of other clients with zquake...
the screen is half-filled with giant red pixels (using +gl_clear 1) like someone got decapitated right next to my screen. in other gl engines, like aguire's, the pixels are grey because i set the gl_clear colour to grey.
fuhquake has this problem, but ezquake does not though. (fitzquake doesn't have the problem either).
does anyone know what that's about?
#151 posted by madfox [84.26.168.11] on 2009/01/07 19:44:06
I made a sprite of the Shambler's bold, this in order to use it in a mod for temperary bold flashes.
Now I'm sofar I can import the sprite in Quake.
I need the sprite to turn on and off.
I don't know if it's possible or I'm missing the logic to understand.
I used this code as bold.qc
$frame 0 1 2 3
void() bold_stand1 =[ $0, bold_stand2 ] {};
void() bold_stand2 =[ $1, bold_stand3 ] {};
void() bold_stand3 =[ $2, bold_stand4 ] {};
void() bold_stand4 =[ $3, bold_stand1 ] {};
void() model_bold =
{
if (self.style >= 32)
{
self.use = light_use;
if (self.spawnflags & START_OFF)
lightstyle(self.style, "a");
else
lightstyle(self.style, "m");
}
precache_model ("progs/bo1.spr");
precache_sound ("ambience/buzz1.wav");
self.solid = SOLID_BBOX;
self.movetype = MOVETYPE_NONE;
setmodel (self, "progs/bo1.spr");
setsize (self, '16 16 16', '24 24 24');
self.think = bold_stand1;
self.nextthink = time + 0.1;
ambientsound (self.origin, "ambience/buzz1.wav", 0.5, ATTN_STATIC);
};
Now I have bold sprite that constantly flashes.
I used the selfuse = light_use; to turn it on or off but it don't seem to work.
Is there a way to turn it on or of with a trigger?
 Well
#152 posted by madfox [84.26.168.11] on 2009/01/13 23:43:52
the logic is probably it is a static entity that can't be moved because it is a MOVETYPE_NONE
Ohter question: I'm coding LostSoul from Doom to Quake. If I give it the normal routines like stand,walk,pain,die and give it a bite like the dog for attack with self.th.melee
all goes right so, I should be glad I can archve it.
The distance the monster reaches while biting to the player is too wide. I don't know how to make it closer.
Then I decided to try the jump scene of the dog. Adding it to the qc worked, but there are some strange sidekicks.
Because LostSoul is a flying monster this doesn't compare with a walkmonster. The lostsoul make a giant jump, but it wants to land onground. And because it is a flying monster this is strange sight.
The monster bumps undergound, than jumps up 64 units, aims to the player, moves 64 units again and then returns to its jump session.
Also the chance of hitting the player is almost harmfull.
I know this is becuase I switch a flymonster with walkmonster code, but would it be possible?
A lostSoul that excellerates its move in air, without the bounce of a walkmonster.
#153 posted by necros [99.227.108.217] on 2009/01/14 00:11:59
to get a flyer to fly toward the player:
take the origin of the enemy (player)
subtract from monster's origin
normalize vector
set monster's velocity with vector * speed you want it to move at.
local vector vec
vec = normalize(self.enemy.origin - self.origin);
self.velocity = vec * 1000;
you'll need to make a touch function to set self.velocity to 0 otherwise, things will get messed up when the monster tries to move from AI.
 Great!
#154 posted by madfox [84.26.168.11] on 2009/01/15 06:47:31
I had to make some prototyping to get my SolJumpTouch run, but now it is a fast Soul!
Thanks!
 MDL Question (cross Posted From Inside3D...)
#155 posted by JneeraZ [24.199.192.130] on 2009/01/16 15:25:57
OK, so inside the MDL file format there is support for simple frames and group frames. I'm trying to get it straight in my head which is good for what.
It looks like things like the walltorch use group frames. Is this so the engine can start animating them on a random frame? I don't see anything in the QuakeC that uses this information so it must be engine side.
Am I thinking about this the right way? Do group frames have other uses?
 Groupies
#156 posted by Preach [86.156.59.51] on 2009/01/16 19:57:21
Basically a grouped frame is a way to make a looped animation on the client side, so the animation changes frame without any input from the server/qc. The advantages are that it uses no network traffic once it starts, and can be applied to a static entity.
From a QC point of view, the entire framegroup just looks like a single frame. Suppose you had a monster with:
regular frames run1 .... run6
a framegroup [idle1 ... idle40]
more regular frames attack1 .... attack8 etc
Then to get at the run frames you'd set
self.frame = 0...self.frame = 5
To play the idle animation you'd set
self.frame = 6
And to get the attack frames
self.frame = 7...self.frame = 14
One of the disadvantages of this arrangement is that the QC has no way of reading where the animation has reached at a given time. This would make it hard to sync a sound with the animation for example.
Open question here...when you have a QC command like self.frame = 6 on a model with a framegroup at frame 6 and NO random flag set, does that command start the animation from the beginning? I suspect that if the frame was already 6 it wouldn't work, as no network update is sent out for a frame remaining the same. If you could get that to work you could do some nice long idle sequences on a monster using them, without running out of frames for important things
So basically the use of them is to cut down on the amount of QC you need to make a simple looping animation. This is vital for static entities which don't have any qc interaction once created(hence static), and can make other things easier.
Another open question paired with a technical fact...If you poke around in the mdl specs like Willem has been doing, you'll notice framegroups come with a value to control the duration of each frame in the group. From my memory of messing with these thing, I could only ever get it to obey the duration of the first frame in the group, the rest of them just automatically followed that. Is that a long standing bug/just Carmack forgetting to add (frameindex*framesize) to the pointer to retrieve it?
#157 posted by JneeraZ [24.199.192.130] on 2009/01/16 20:54:27
I thought that the animations ran at 10Hz or something and that was that. I know the spec has that array of floats that are claimed to be timings, but nobody ever talks about them so I sort of assumed that they were always set to even intervals or just plain didn't work.
All the fire and stuff in Quake seems to animate at the same speed, at least to the naked eye.
#158 posted by necros [99.227.108.217] on 2009/01/16 21:12:21
i could never get the framegroup animation speed thing to work from within qme3.1 :S
#159 posted by JneeraZ [24.199.192.130] on 2009/01/16 21:17:27
Could someone with engine familiarity confirm or deny if that code works or not? I'll bet Preach is correct that either it's being ignored intentionally or Carmack has a bug in the engine where he doesn't read the values in correctly and never noticed.
 Well
#160 posted by Preach [86.156.59.51] on 2009/01/17 00:24:13
Admittedly when I managed to get different rate framegroups to work I was using darkplaces, so it's possible that regular engines have no support for it and darkplaces had slightly broken support for it, I will go away and check this weekend(hopefully).
As for the 10Hz thing, it isn't hardwired into quake that things animate at that speed, but there are 4 reasons why it is almost exclusively used.
1: It's the rate at which all the existing quake models are animated. So anything new usually follows that pattern.
2: The QC shorthand way to define animation functions in quake like
void() ogre_stand6 =[ $stand6, ogre_stand7 ] {ai_stand();};
implicitly assume a 10Hz rate, they insert a self.nextthink = time + 0.1; at the start of the function. You could change that in the function body:
void() ogre_stand6 =[ $stand6, ogre_stand7 ] {ai_stand();self.nextthink = time + 0.05;};
but it's awkward, and also the original nextthink remains before it.
(I think a nice fix would be a way to specify $fps in the $frame macros, and then have the compiler insert the correct nextthink time when expanding animation functions. But I've barely managed to get FTEQCC to compile, so it may never happen.)
3. It is the framerate which the game will guarantee - if the game is being so slow that it can't achieve 10 fps then it will slow down game time. You might set thinks every 0.05 seconds and have them still occur every 0.1 second in game. Of course, in the real world quake is 10 years old and so never runs slow, but it's a nice theoretical.
4. The other limits of the mdl format start to show once you start animating at higher framerates. 256 frames only gives you 12 seconds of animation at 20fps, and you have to cram all of a monster's death/pain/attacks into that length of time. Often doable, but pretty tight. Also, the compression of the vertex coordinates means you get rapidly diminishing returns on increasing the framerate. The result wobbles might be worse than keeping 10fps and letting the engine interpolate at higher precision.
I don't think any of those things is enough to completely kill working at higher framerates though. What I'd like to see is some specified use of it. Keep 10 fps on unimportant/low motion animations like idle poses. But when you have a big sweeping motion like a sword slashing, increase the framerate for that to 20. This gets around both of the problems of point 4 there.
If you do run into problems where you have too many frames to increase the framerate, it may be possible to abuse framegroups to provide the interpolation you need. This does rely on two things - that you can set custom framegroup fps, and that when you enter a non-random framegroup from a different frame, it starts animating from the beginning.
#161 posted by JneeraZ [71.70.208.255] on 2009/01/17 12:25:26
OK, so in further poking around am I right to assume that an MDL will either be using simple frames OR group frames? There's no mix and match going on, correct?
 Combined Force
#162 posted by Preach [86.153.44.164] on 2009/01/17 20:16:06
You can in fact have both in the same model, it is possible to combine the zombie crucifiction frames into one framegroup and make crucified zombies static(but then you don't get the random duration of frames or the sounds, so it's not a PRO TIP or anything). Doing that doesn't affect the rest of the frames in the model, so regular zombies work as normal.
Also, changing the rate is inconsistant: in glquake engines the duration is taken from the first frame, in winquake it reads each frame duration correctly. There's an argument there that the bug should be fixed in glquake engines there, but best practice is probably to use the same rate for the entire framegroup, and set it in each frame so that winquake handles it the smae.
The bad news is that when rendering a framegroup which isn't random, the frame to render is just calculated from the world clock, rather than the time since that framegroup was set (That is assuming I've read the relevant code correctly). This means you can't abuse framegroups to provide increased interpolation with the same number of frames on the QC side.
#163 posted by JneeraZ [71.70.208.255] on 2009/01/17 20:29:31
Ahh OK. Well, good to know then. i'll need to handle it all gracefully then, no shortcuts. :) Thanks...
 Framegroups
#164 posted by madfox [84.26.168.11] on 2009/01/17 22:58:15
When I tried to combine the skull of Lostsoul with the flame2.mdl I was overtaken by the fact that Quark407 in model import reakts:
can't handle framegroups.
Is there a way to break this options so I can manipulate the modelframes?
#165 posted by necros [99.227.108.217] on 2009/01/18 00:34:33
open flame2.mdl in qme, remove frame groups, save, open in quark.
#166 posted by madfox [84.26.168.11] on 2009/01/19 13:15:00
framegroups, does this mean
the parts of vertices within a frame like the different flame parts,
or different frames?
The only way to avoid this "no framegroups supported" for me is by exporting a flame2.dxf and import it back as a new model. Then I can reimport the multiple frames, and quark can import it.
#167 posted by JneeraZ [24.199.192.130] on 2009/01/19 14:59:11
Frame groups, as I've come to learn over the weekend, are basically a collection of frames that are special in that they will animate autonomously without having to tell the server about it. Each frame is a complete animation frame, just like the simple frames in other models.
 So
#168 posted by madfox [84.26.168.11] on 2009/01/19 17:43:16
the different parts in one frame make quark tell it is a framegroup.
I know nothing about servers and how it works in quake.I just wondered why one frame left in qmle after deleting all other frames in flame2.mdl still errored quark with framegroups.
It is the same error I had after decomposing a death frame to divided parts. After saving they were all melted together again.
 Animated Skins
#169 posted by JneeraZ [71.70.208.255] on 2009/01/20 21:25:26
It looks like MDLs have support for animated skins but no MDL that I ever open has one. Can anyone recall a model that had an animated skin on it in a mod or anywhere else?
 No,
#170 posted by necros [99.227.108.217] on 2009/01/20 21:54:38
but i believe you are refering to skingroups?
i've heard people talk about that but never found out how to do it, myself.
#171 posted by JneeraZ [71.70.208.255] on 2009/01/20 22:03:11
Sorry, yes, skin groups. I see them in the spec and was just wondering if they've ever actually been used. I guess once these tools are further along I'll just test them out and see what they are.
 Have You Watched The Cutscenes
#172 posted by RickyT33 [82.20.37.149] on 2009/01/20 22:05:06
on Nehahra? They have like facial animation as in the mouth texture has two frames. Also isn't there some blinking?
#173 posted by JneeraZ [71.70.208.255] on 2009/01/20 22:08:24
Well, how are these skingroups used? I'm going to assume that it's like the frame groups - some sort of automated animation system. If that's the case, I guess they could have had a moving mouth with blinking thrown in here and there to make it work (no lip syncing at all but that's probably a given in the Quake engine).
 Ricky
#174 posted by necros [99.227.108.217] on 2009/01/20 22:20:09
i believe the talking and blinking (not sure about the blinking, that may have just been random?) was handled via impulse commands and that the 'actor' players would do that themselves. or it just occured to me, they maybe did it in post in a demo editor.
 Hmm
#175 posted by HeadThump [4.136.90.159] on 2009/01/20 22:51:59
just to clarify, do you mean something like painskins (sweeeet)?
http://www.inside3d.com/showtutorial.php?id=95
Or, an animated concurrent effect?
 I Like Painskins!
#176 posted by RickyT33 [82.20.37.149] on 2009/01/20 23:12:17
i managed to do that once when i was about 15.
Bring back painskins!
#177 posted by JneeraZ [71.70.208.255] on 2009/01/20 23:38:21
HT
No, that tutorial looks like it's just bumping up to another skin index. The skingroup stuff looks like an auto animate deal.
Preach! :)
 *We* Seem To Be Going Round Twice...
#178 posted by Preach [81.155.192.36] on 2009/01/21 00:16:01
You can auto animate skins, it's pretty much the same deal as the frames, you can designate a collection of skins as a single skingroup, they autoanimate according to timings set in the model. I have no idea if the random flag works on them, or if the same glquake bug for duration exists. If you want an example of a model which does it, dig in the quoth pak1.pak for a model called pickup.mdl. The last two skins, which are for the health and megahealth, have such animations to make the lights blink.
Necros: how you do it in qme is arrange the skins in order, then right click on the first one and select "Append Skingroup To Previous Skingroup". Repeat until all the skins in the animation are combined, and then save the model again.
 Skingroups
#179 posted by metlslime [67.180.230.20] on 2009/01/21 00:19:55
i'm pretty sure these are the analog to framegroups in models and sprites, basically client-side looped animation.
based on the engine code, it looks like glquake has pretty half-assed support for skin groups, for example every skin is given 4 pointers to textures, and almost all the time the 4 pointers are to the same texture, but when loading a skingroup it gives them unique pointers. If you have more than 4 skinframes, it drop some.
So effectively you can only have 1, 2, or 4 skinframes in a group in glquake. If you have 3, it will animate 1, 2, 3, 1, 1, 2, 3, 1... and if you have 5+, it will animate (e.g.) 5, 2, 3, 4, 5, 2, 3, 4...
Also, not sure if the model format supports intervals for skingroups, but glquake clearly only does 10Hz animation for them.
My guess is there's one model somewhere in the mission packs using this feature, and that required them to add this minimum of support to glquake when they wrote it.
 Mother Of God
#180 posted by Preach [81.155.192.36] on 2009/01/21 00:52:14
Christ metlslime, pull the curtain back again, that's hideous!
Informative though, cheers really.
#181 posted by JneeraZ [71.70.208.255] on 2009/01/21 01:01:30
Haha, horrible! Well, good to know that supporting that can go at the bottom of the priority list at least. :P
 Well
#182 posted by ijed [216.241.20.2] on 2009/01/22 16:24:15
Blinking health items at least.
Possibly some really shitty animated soul sphere swirling is possible . . . in four frames.
Can't think of a decent monster application - glowing eyes?
#183 posted by JneeraZ [24.199.192.130] on 2009/01/22 16:27:54
"Blinking health items at least. "
Huh, that's true. OK, I guess that'll be my test case for loading skin groups then.
#184 posted by JneeraZ [24.199.192.130] on 2009/01/22 16:29:00
"Can't think of a decent monster application - glowing eyes?"
I think many cool ideas could be done there. Glowing demon eyes, blinking lights on enforcer armor, blinking eyes, etc. Could be neat.
 Pain Skins!!!
#185 posted by RickyT33 [81.157.18.236] on 2009/01/22 16:31:57
pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!pain skins!!!
#186 posted by JneeraZ [24.199.192.130] on 2009/01/22 16:34:21
To be honest, pain skins don't really excite me in Quake because how often is a monster in pain? You see the monster and it's generally dead within seconds. Would you even see the pain skin kick in?
 Its Just A Daft Thing I Wanna See Really
#187 posted by RickyT33 [81.157.18.236] on 2009/01/22 16:58:51
Monsters are all a bit bruised/bloody anyway, but brown grunt stood up, 2 seconds later red and bloodied grunt on floor. I mean I know that the pain skins would be non-locational, but for monster like a Shambler or a Vore you could have three or four increments of pain, relative to HP, and it would show how close that Shambler you've been picking away at with an SG or SSG for five minutes is to death!
I just think it looks cool. I also wanna see a mod with pain skins and zombie-gib blood splats dribbling down walls from when mosters are shot.
I know its meant to be easy in Quake C, theres a tutorial on Inside3d. Maybe this will be my first Quake C project . . .
(I had it working once when I was about 15, but I cant remember how it worked now, and haven't tried yet)
#188 posted by JneeraZ [24.199.192.130] on 2009/01/22 17:11:35
Dead skins might be a decent idea. The corpse on the ground could be all fucked up and bloody. That might make more sense...
 Ok, Pain Skins In 5 Minutes
#189 posted by Preach [86.148.15.145] on 2009/01/22 20:01:52
Lets say we work with the grunt, and give him a second skin which is bloody and beaten up. Now open up soldier.qc and look for the function
army_pain
Right at the bottom of this function, add
if(self.health < 15) //if we are below half health
self.skin = 1;//turn on the pain skin
This will work a lot of the time, but there's a chance that the grunt goes from above 30hp to dead without going into pain. Also, if the grunt is dead, we should check if he gets gibbed, and set the skin back to 0 if so, because the grunt head only has 1 skin. So find army_die
and put
self.skin = 0;
just after
if (self.health < -35)
{
Then put
self.skin = 1;
after the closing } bracket of that gib section of the function.
You can do a similar thing with pretty much any monster, find the pain function and use that to add the pain skin. Remember that some monsters don't automatically go into pain animations, and may return near the top of the function. This means that you have to think about where to add the line. You could put it right at the top, so that it always gets checked. Or you might decide that the skin should only change if the monster goes into pain, and so put it at the bottom.
 Pain Skins
#190 posted by necros [99.227.108.217] on 2009/01/22 21:17:09
could have a practical purpose...
assuming your were consistent and always used pain skins for, let's arbitrarily decide 50% hp.
you could make like a monster that 'heals' wounded monsters if they are below 50%. you'd have a visual indicator for what's happening and it could be a cool new mechanic.
well, maybe something more complex would be in order like 'heals the monster to 90% of maximum health.' so each time it heals, the max health goes down and you could put in a check where it wouldn't be able to heal if the current max health is less than half of the actual max health.
#191 posted by JneeraZ [71.70.208.255] on 2009/01/23 01:37:41
Oh duhr ... I can't use the health packs as a test case for skin groups in MDLs because those aren't MDLs (they're BSPs). Heh. Oh well...
 After Giving It Some Thought
#192 posted by HeadThump [4.136.90.99] on 2009/01/23 08:55:59
I think I know what Willem's next project is: Iron Man Arena, and he needs the effects on the player models to simulate the repulsor beam socket, and the jet flames coming from the boots. Imagine hovering around firing missiles and repulsor beams at one another with Twig or Gyro2 physics to both impede and improve our navigation. Oh, this is going to be sweet.
Am I close?
 Dead Skins
#193 posted by ijed [216.241.20.2] on 2009/01/23 13:27:21
Is interesting - pain skins doesn't really do it for me since most monsters are bloody anyway, and shooting a fiend in the back for some bloody mess to appear on, say, it's face is counter to what you're trying to achieve with the effect.
You could paint a handful of skins per monster and have them directional, but that misses the point of multiple damages - you'd only be able to have one active skins since you can't apply decals.
Dead skins is more interesting idea - you have the creature vomiting blood and caked in dirt. Problem is it started bloody, will anyone notice?
You could go whole hog and have a Mancubi style death - for example the Shambler's stomach could rupture when he dies, but then it probably wouldn't look very good with a single frame change and no 3d animation.
Healing enemies is good, like a Q2 medic form, but in order to show that monsters are injured I'd prefer to have them bleeding; particles dripping from them.
#194 posted by JneeraZ [24.199.192.130] on 2009/01/23 15:05:16
"Dead skins is more interesting idea - you have the creature vomiting blood and caked in dirt. Problem is it started bloody, will anyone notice?"
On some you would. You would definitely notice a change in a shambler, enforcer or grunt. Creatures like ogres would be tougher but it might still be worthwhile.
 Pins Skins Pain Skins Pain Skins
#195 posted by RickyT33 [81.157.18.236] on 2009/01/23 15:17:40
monster <70 %
Some more blood around the chest and a little on the back, face and arms, some dripping down upper legs
monster <30 %
Big hole in chest, large exit wounds on back (i.e. gored up) more drippind down arms and legs
monster dead
Some blood particles flowing from the monsters midrift and maybe neck/face
monster -howevermuch it might be %
Gibbed!
It makes sense, you know it does. In a game so abstract that you can gib monsters in the style you can already, it would only add pleasure to my experience :D
 Dead
#196 posted by necros [99.227.108.217] on 2009/01/23 19:25:43
You could go whole hog and have a Mancubi style death - for example the Shambler's stomach could rupture when he dies, but then it probably wouldn't look very good with a single frame change and no 3d animation.
for the zdoom md2 models, they did seperate models for the monster deaths. the 3d mancubus death looks pretty good, as does the cacodemon.
i think if someone wanted to take the time, they could revamp the old death animations in that same sort of style for quake with new models.
 Willem And Bsp
#197 posted by Preach [81.153.25.42] on 2009/01/23 19:29:05
There's a mdl version of the health box (and indeed all the ammo pickups at the same time) included in quoth, which would be suitable for your testing. You'll have to extract it from pak1.pak, and it's called pickup.mdl.
#198 posted by JneeraZ [24.199.192.130] on 2009/01/23 19:40:26
Sweet, will do! Thanks for the heads up, Preach.
#199 posted by JneeraZ [24.199.192.130] on 2009/01/23 19:41:25
Oh, and it just occurred to me ... so THAT'S how you supported rotated pickups then. Neat!
 Rotated Pickups
#200 posted by Preach [81.153.25.42] on 2009/01/23 21:40:09
You can rotate pickups in their regular quake form. The only problem is that the bounding box doesn't change when you do that, which is compounded by the fact that the ammo boxes rotate about one of their corners, and not their centre. If you rotate them 180 degrees, the model entirely escapes the bounding box!
The quoth fix is just to put the bounding box in the right place relative to where the model get rotated to. The advantage of using the .mdl version of the ammo is that it saves you up to 10 model precaches, which can be helpful if you're pushing the limit(Stark Monstrosity showcases this feature).
The side effect of the .mdl version is that the crate is lit according to the ground below, rather than the baked in light levels of the regular ones. In order to stop crates getting lost in the dark, we a: disabled it by default and b: added small fullbright markings to all of the ammo. The shells and nails had these already, so it was natural to extend the idea to the other ammo.
 I Drew The Line At Cutting Out Monster Head Gibs
#201 posted by RickyT33 [82.20.37.149] on 2009/01/23 21:52:51
you can cut those out too.
I did however use the combined ammo .mdl flag at the same time as the one preach described. I like the fact that you add the two flags together, seems like a smart system.
 Heheh
#202 posted by Preach [81.153.25.42] on 2009/01/23 22:43:52
If it's a smart system, it was invented by a smarter person than myself. It is in fact the same system that spawnflags use - the spawnflag for "not in easy" is 256, "not in medium" is 512, and so "not in easy or medium" is the sum of the two.
In both cases, the values you have to set are chosen to by successive powers of 2( 1, 2 , 4, 8, 16, 32...)
These numbers are chosen because the sum of the first n-1 numbers is always 1 less than the nth number. That way, the sum of any subset of them is unique, and any number you chose corresponds to some combination of them.
There's also a connection with how binary numbers are stored as integers. So if you know about that, you can think of the nth 0 or 1 digit in the binary representation being on or off according to whether the nth option has been selected.
 Preach
#203 posted by ijed [190.20.66.157] on 2009/01/27 01:18:29
Did seeting them fullbright look bad?
 $frame Question
#204 posted by JneeraZ [71.70.208.255] on 2009/01/27 14:08:24
OK, so I'm trying to get MDLEd fully functional and I have questions about QuakeC and MDL files...
Do you have to have a "$frame blah1 blah2 etc" for every animation frame in the MDL?
Do they have to match the internal structure of the MDL (do the frames have to be stored in the same order as the $frame lines in your QC file)?
What I'm getting at is this ... will I have to allow the user to have full control over the ordering of the frames in the MDL file or can I safely/automatically sort them alphabetically? Does it make a difference?
 Afaik
#205 posted by necros [99.227.108.217] on 2009/01/27 19:36:20
the $frame walk1 walk2 at the beginning just macros those strings to a number, and that number starts at 0 on the first $frame declaration and increments by 1.
so walk1 actually means frame 0, so frame 0 needs to be your walk1 frame.
in other words, the order of those $frame declarations are important and so can't be re-ordered without re-ordering the frames too.
 Fullbright$ And $frames
#206 posted by Preach [81.153.24.36] on 2009/01/27 19:41:58
ijed: as far as I know, there is no standard way to make a .mdl fullbright. It's just one of the differences in the way the two types of model get rendered, bsp have their own lighting info, and mdl use the map's light levels. I do think that medpacks looks pretty cool in .mdl format when placed in dark corners, it makes the lights blinking away on them really stand out.
Willem: You must at least make sure that you don't alter the order in which the frames occur without giving the user control over it. The actual names given to the frames in the .mdl aren't used by the engine/qc. It relies entirely on the enumeration of them in the order that they occur.
The $frame macros are simply a way of defining recognisable constant names for the numbers 0....n in a quick manner which only lasts for one qc file. The qc compiler has no knowledge of what the actual model file contains, so it just substitutes a frame number for each instance of $stand4 with a 3 - assuming that $stand4 is the 4th $frame that it encounters in the header.
So if your program loaded in ogre.mdl, reordered the frames into alphabetical order and then saved them again, the animations would no longer match up, so that would be bad. As long as you ensured that frames were exported in the same order they were imported, you would probably get away with it. But I suspect it would still be a desired feature...
(As a possible side note, people making qc files don't have to define the $frame things for every frame, they can just use the numerical indexes, or a mixture of the two. But just using the numbers can mean a lot of code has to be changed if you extend your first animation loop from 6 to 8 frames, so it's not encouraged to do that for anything with multiple sequences)
#207 posted by JneeraZ [24.199.192.130] on 2009/01/27 21:08:07
"You must at least make sure that you don't alter the order in which the frames occur without giving the user control over it. The actual names given to the frames in the .mdl aren't used by the engine/qc. It relies entirely on the enumeration of them in the order that they occur. "
Beautiful. OK, that settles that then! Thanks.
 Hmm
#208 posted by nonentity [87.194.146.225] on 2009/01/28 07:38:41
Hey coding thread.
Very sorry about this, never post in here since I'm not a coder, so tend to skim read and leave you guys to your scary quote text fun ;p
Just wanted to bump stuff above the flame thread again (I suggest anyone else reading this does same and avoids bumping again pls ;)
Kiss
 MDL Hell...
#209 posted by JneeraZ [71.70.208.255] on 2009/02/05 14:08:57
Man, this file format is fairly jacked up.
Anyway... Quick question:
Is the "onseam" stuff entirely necessary for texture coordinates or is that some sort of concession that was made to allow for easy skin creation back in the day? If I store all texture coordinates as full 0-1 values and set onseam to zero for them all, will Quake throw a fit?
 Onseam Bowling
#210 posted by Preach [86.150.195.44] on 2009/02/05 17:39:00
When making new skins, it's no longer really necessary. If you're trying to do anything more complicated that 2-sided planar then you pretty much have to ignore it, and just eat the extra vertices on the model. The md3tomdl converter does exactly this.
However, it's very important that you keep them for existing models, as it tells you which vertices need to be duplicated on the skin. I think if your program didn't preserve the original quake models like that, people would get confused to say the least.
If you changed models to duplicate vertices which were onseam, and then removed the onseam flag, there could problems in other editors. For example, if you saved one like that, then loaded it and saved it with QMe, then the vertex normals along the seams would be altered compared to the original, which might make the seam more obvious.
#211 posted by JneeraZ [24.199.192.130] on 2009/02/05 18:18:16
Wow, so the whole purpose behind it was to save a vert or three in the mdl file?
 Hmm
#212 posted by nonentity [87.194.146.225] on 2009/02/05 18:21:39
Bear in mind we're talking the first full 3D fps here.
What we now view as insane levels of optimisation was fairly necessary back then...
#213 posted by JneeraZ [24.199.192.130] on 2009/02/05 18:25:21
I question some of the stuff, actually. Carmack did some crazy machinations in places to save very minimal amounts of space.
 Ijed
#214 posted by gb [89.27.229.62] on 2009/02/05 19:13:49
We need to think about skin animations. Blinking lights on enforcers are neat, and I have a couple other cases where this could be useful.
Apart from that. Do the additional mouth/face textures often seen on id skins have something to do with this?
Were they meant for animation purposes?
#215 posted by JneeraZ [24.199.192.130] on 2009/02/05 19:17:13
I think those are for the head gibs.
 Gib Faces
#216 posted by onetruepurple [79.191.236.214] on 2009/02/05 19:53:17
Would be a perfect addition for death skins (if they get implemented somewhere)
 Maybe
#217 posted by Preach [86.150.195.44] on 2009/02/05 20:00:32
I'd guess the whole onseam system was created because at the time it seemed like an unintuitive system to have vertices occupying the same position in the model, but connected to different triangles - when they are supposed to be part of the same surface in the model. The onseam method was a fix to the problem "how do I display the same vertex in two places on the skin?". It's just unfortunate that the solution pretty much ties you to the front/back skins that quake used.
Although I usually advocate the detached vertex solution, detaching things like that can cause problems. For example when calculating the vertex normals at that vertex, you probably want to average all the surfaces meeting at the split vertices, and give that same vector to all the vertices. This is a lot harder to do once you've split the vertices. In fact, if an unrelated vertex just happens to collide then you're scuppered...
Thankfully, .mdl uses precomputed vertex normals, so as long as you're converting from a format that supports merged vertices with split UVs then you can probably get sensible smoothing groups. Also, worrying about smoothing groups isn't the most pressing concern with quake models.
Interestingly enough, I don't know that onseam actually saves memory over all, when you consider how much wasted texture space there is as a result of using it. On models with lots of frames it's probably beneficial as the extra vertices would be recorded on all those frames. But for weapon models and other simple models, onseam probably doesn't make up for the waste.
#218 posted by gb [89.27.229.62] on 2009/02/05 20:19:43
I think headgibs use their own models, which use their own skins.
 I'm Aware Of That
#219 posted by onetruepurple [79.191.236.214] on 2009/02/05 20:29:18
How difficult would it be to copypaste the faces from the head gib skins onto body skins? (I'm no modeller so I can't tell)
 Yeah
#220 posted by ijed [190.20.113.58] on 2009/02/06 00:14:34
I want blinking lights for the enforcers, that was a good suggestion, whoever made it.
It looks from the models that the head gib was originally going to come from inside the main model, but it didn't work out.
Simple as export c+p import to put the pain head onto the normal guy for a dead skin.
#221 posted by gb [89.27.229.62] on 2009/02/06 00:24:48
I was replying to Willem about the additional face parts etc. on id1 skins. Those are pretty weird.
 So Was I
#222 posted by ijed [190.20.113.58] on 2009/02/06 02:03:42
It seems the extra faces are there because the head and model were originally going to be combined, until they realised that hiding the entire body inside a copied head would be more wasteful.
 Just Think....
#223 posted by metlslime [64.175.155.252] on 2009/02/06 05:09:37
how awesome it would look if they did hide the body inside the head gib, now that we have engines that do model interpolation?
 Vampires!
#224 posted by Preach [86.150.195.44] on 2009/02/06 10:07:26
Back in the day before I worked on mods that people would play, I made a quake mod where you fought vampires - aping Buffy and that kind of thing. One of the driving things behind it was to make the death sequences look cool (by quake standards), so when you staked a vampire through the heart they'd look agonised for a beat, then explode into a puff of dust.
Coming back towards relevance, when you killed them with fire the flames burnt upwards from their feet while their arms flailed. In order to make their legs disappear, the polygons were just folded up into the upper legs, then the torso, with the flame graphic concealing the interpolation which arose. I imagine the final effect is not too dissimilar to what metl's thinking of.
(ps: the head gibs are probably separate for the more mundane reason of giving them a blood trail, which is a per model effect...)
 Railgun In Quake
#225 posted by spy [92.47.190.20] on 2009/02/06 10:43:02
is it possible?
i'd appreciate any help
#226 posted by Spirit [80.171.52.172] on 2009/02/06 12:20:07
Sure, there were some mods with railguns I think.
 Ahem
#227 posted by Spirit [80.171.52.172] on 2009/02/06 12:21:03
And I just remembered I once successfully completed this tutorial: http://www.inside3d.com/showtutorial.php?id=167
#228 posted by Trinca [194.65.24.228] on 2009/02/06 12:28:32
Spy Parboil once change the qwprogs.dat to railmod i think... since u are russian is easy to ask in is forum :)
http://parboil.quakeworld.ru
#229 posted by Trinca [194.65.24.228] on 2009/02/06 12:47:58
zomggg are you the spy from the old Parboil board?
hehe
 Quakec Question...
#230 posted by metlslime [24.130.223.174] on 2009/02/06 12:57:59
what is the proper way to make an entity toggle between visible/solid and invisible/nonsolid?
So far, what i have tried is calling self.modelindex = 0, self.solid= SOLID_NOT to make it invisible, then doing SetModel(self, self.model), self.solid=SOLID_BBOX again to make it visible.
Visually, it works. But, once it's been invisible, it can never turn solid again.
So, is there a better way?
 Trinca
#231 posted by spy [92.47.190.20] on 2009/02/06 13:18:01
what are you talking about?
psssst. trinca don't tell anybody that i'm russian it's a secret :))
p.s. thanks spirit for the link.......
 Zomggg
#232 posted by spy [92.47.190.20] on 2009/02/06 13:19:18
i think i'm drukn again
 (in)Visible
#233 posted by Preach [86.150.195.44] on 2009/02/06 15:30:46
To make it invisible and non solid, the following should suffice:
self.model = "";
self.solid = SOLID_NOT;
Not sure if adding self.modelindex = 0 adds anything to that, it might stop it being sent over the network.
To restore it again, use:
setmodel(self, *modelname*);
self.solid=SOLID_BBOX;
If you don't know *modelname* at compile time(eg a func_wall where the model is loaded from the map), then you need to stash the model info somewhere safe. Put a line like
self.mdl = self.model;
somewhere in the spawn function, and then use self.mdl in place of *modelname*.
If you're still having problems, try adding a call to setsize after setmodel
 Thanks For The Help...
#234 posted by metlslime [24.130.223.174] on 2009/02/07 11:17:45
i finally got it to work, and here's how.
1) to enable being solid after turning inivisible and then visible again, i only ever set the model using setmodel once, and from then on alternate between setting modelindex to 0 or the actual index.
Since setmodel is never called, the entity stays linked into the world with the original physics bounds. self.solid can be changed without issue.
2) for entities that are set to START_OFF, there was still a problem where they'd never appear at all, and never become visible. My hack solution is to wait 1 second, then make them invisible/nonsolid in a special think function, rather than in the spawn function.
 Good
#235 posted by madfox [84.26.168.11] on 2009/02/07 17:52:32
explanation to make a monster invisible.
I'm still trying to find the right colours to improve Spectre in its translude way.
And as it is a sprite it has a funny way of walking. I think more darker colours on the outside and transparant inside.
http://members.home.nl/gimli/spectr.jpg
 Can Be Shot But Doesn't Collide With Walking?
#236 posted by JneeraZ [71.70.208.255] on 2009/02/13 21:52:05
I'm probably going to think of the solution 5 seconds after asking this but ... let's say I want a monsters corpse to be shootable but I don't want it to collide with other corpses or the player. I just want it to react to gunfire (both instant hit and missiles).
Doable?
 Look At The Corpse, It's Voodoo QC Dancing...
#237 posted by Preach [217.44.219.227] on 2009/02/14 01:59:02
It can't be done easily. I say that because darkplaces has an extension for just this purpose, where you can make an entity SOLID_CORPSE, which behaves like you say. The following is ugly, not only in itself, but also in the dark secrets about standard ID1 code it exposes. Read on if you dare...
The key thing is that you can't change the .solid status of things during touch functions, it can cause engine crashes. So, the vast majority of the time, you want your corpse to be the same .solid type as a trigger_multiple entity, which is SOLID_TRIGGER.
We're going to use the grunt as our test dummy here. This is the kind of thing you need to do in your death sequences, during the frame that usually makes the monster SOLID_NOT:
void() army_die3 =[ $death3, army_die4 ]
{
self.solid = SOLID_TRIGGER;
setmodel(self, self.model);
self.touch = corpse_touch;
self.health = 20;
self.takedamage = DAMAGE_AIM;
self.th_die = GibPlayer;
self.th_pain = SUB_Null;
self.ammo_shells = 5;
DropBackpack();
};
We make it SOLID_TRIGGER, then call setmodel in order to link it, which prevents a "trigger in clipping list" crash. We make it's touch function corpse_touch, see below. We also make it damageable again, give it 20 hp, and define both th_die AND th_pain, the latter being important if you don't want to reanimate your corpse.
So here's the deal. In this state(SOLID_TRIGGER), when a missile collides with one, you get a touch event where the trigger is self and the missile is other. You do not get one where the missile is self and the trigger is other! I'm not sure if this is an optimisation just for missiles, or that any entity touching a trigger doesn't set off its own touch function. In any case, we're about to cheat:
void() corpse_touch =
{
local entity oself;
if(other.movetype != MOVETYPE_FLYMISSILE && other.movetype != MOVETYPE_BOUNCE)
return;
oself = self;
self = other;
other = oself;
self.touch();
};
See what we're doing? The first bit of code is just so that we don't bother doing anything if we aren't hit by a missile. You might want to use a different criteria for what is a missile, I went for something that required no changes elsewhere. Then we create a touch event on the missile by the trigger, but by hand instead of from the engine.
Once you've done that, you might think we're done for missiles now, and you can give it a try by lobbing a grenade into a corpse. It'll explode on contact as desired (you can of course change the corpse's .takedamage to DAMAGE_YES if you want to prevent grenades from detonating on contact, I set it like this for illustrative purposes). However, if you fire some nails into your corpse, you might be surprised to find nothing happens.
The reason for this is due to some entirely redundant code in the original QC, which must have been moved engine-side for performance, but then remained in the QC source by mistake. Look at the start of spike_touch in weapons.qc:
void() spike_touch =
{
if (other == self.owner)
return;
if (other.solid == SOLID_TRIGGER)
return; // trigger field, do nothing
...
You'll actually notice the first line in the code for almost all quake missiles. It's totally pointless, as the engine never makes collisions between entities and their owners. Just think how many times that code has been called in a million deathmatches across the world, and not once has it been true...
As we discovered near the top of this section(and to be honest I never knew about this before I tried today), SOLID_TRIGGER entities don't generate touches on missiles either, so the next line is similarly pointless. To get things working, comment both statements out, and do the same in superspike_touch. If you're bored, get rid of the self.owner lines in the grenade and the rocket.
If all has gone to plan, at this point all the missiles will damage the corpse.
Join us after the break when we investigate the shotgun and other tracelines...
 You Can't Talk To A Man With A Shotgun In His Hand...
#238 posted by Preach [217.44.219.227] on 2009/02/14 02:59:57
Before we start the business proper, I should alter you to two bugs with the code which only became apparent once the grunts started hitting corpses with their shotguns. The first is that when monsters begin infighting, they don't realise that their target monster has died when they become a corpse. This is because they consider their enemy dead if their health is below 0, but the corpse has positive health. The fix for this is left as an exercise.
Also, if the corpse gets damaged by another monster, it will get resurrected. To prevent this, add the line
self.flags = self.flags - (self.flags & FL_MONSTER);
when creating the corpse.
~~~~~~~~~#~~~~~~~~~
Ok, so the question is, how do we deal with weapons that use a traceline. And the solution is we make the corpse solid only for long enough to perform the tracelines. We in fact toggle the solid state of all the corpses in the map. Although in theory we might end up changing the solid status of something during a touch function(if a touch caused a shotgun to fire, for example) we hopefully* put everything back before the engine can notice.
So the simplest way I could think of to change all of the corpses to solid and back was: give all of your corpses the classname "corpse", then use the following functions to toggle the solid status:
void() corpse_solid_on =
{
local entity corpse;
corpse = find(world, classname, "corpse");
while(corpse)
{
corpse.solid = SOLID_BBOX;
setmodel(corpse, corpse.model);
corpse = find(corpse, classname, "corpse");
}
}
void() corpse_solid_off =
{
local entity corpse;
corpse = find(world, classname, "corpse");
while(corpse)
{
corpse.solid = SOLID_TRIGGER;
setmodel(corpse, corpse.model);
corpse = find(corpse, classname, "corpse");
}
}
The trick is then to surround calls to traceline with these functions. The axe is very simple, just put corpse_solid_on(); on the line above the traceline and corpse_solid_off(); on the next line after it.
For the shotgun, it's worth remembering that there are lots of calls to traceline in a single blast, and since toggling the solid status is fairly expensive in terms of performance, we should do it once per blast. So sandwich the functions around the
while (shotcount > 0)
{...}
block.
The lightning gun is left as a small exercise, but it's only really worth wrapping the first traceline in the function, the other two are basically enormous bugs which speedrunners exploit to kill things through walls.
That's almost it, but there's one finishing touch. If you go up point blank to shoot a corpse, you'll find that your shot disappears, or attack does nothing. This is because the traceline starts inside an entity, and so the returns from the traceline are a bit weird. The telltale signs of this happening are:
trace_fraction == 1 (not 0 as you'd expect)
AND
trace_ent != world (if it is world, then the trace really did hit nothing)
So what we do is add a bit of extra code which can cope with this case to the various weapon attacks. As an example, add the following code just below
if (trace_fraction != 1.0 )
TraceAttack (4, direction);
in the shotgun firing code:
else if (trace_ent != world) //if so, we are stuck inside what we have hit
{
trace_endpos = src + direction*16; //set some reasonable values
trace_fraction = 16/2048;
trace_plane_normal = -1 * direction;
TraceAttack (4, direction);
}
The code for the axe/lightning gun is similar, but if people get stuck on that exercise I can supply good fixes.
Well, that wraps things up for today. I would say that this latter part is quite an ugly hack, but the code in the first post is actually fairly clean. In all cases you should ask yourself "Would I show my mother this code" before you do something you might regret.
As a final parting thought, you might want to adjust the height of the bounding box of the corpse from the default, so that shots at head height don't blow up the corpse. If you do, remember that you need to do this in both of the corpse_solid toggling functions.
*I say hopeful, but I'm pretty sure it should work. I'm just not sure how careful the engine is at checking, and it's such an awkward thing to create a test case for. So I'm gonna be cautious in my endorsement.
#239 posted by JneeraZ [71.70.208.255] on 2009/02/14 11:14:18
Preach, you are fucking awesome. :) Thanks man, I'm off to digest all of that.
#240 posted by JneeraZ [71.70.208.255] on 2009/02/14 12:59:11
Absolutely beautiful, that all worked. Thanks again!
 Yeah
#241 posted by ijed [216.241.20.2] on 2009/02/18 14:05:06
That's very nice, thanks for the explanations.
 Bit Of A Backtrack
#242 posted by Preach [86.160.143.42] on 2009/02/19 22:17:00
A few pages ago I said QC only checks the first component of a vector when evaluating boolean logic on them. This is not always true.
if((!'0 1 1'))
will work correctly - notice the double brackets. If you take the inner brackets away, then it stops functioning correctly on compilers which perform optimisations. Here is why:
When an if statement is compiled, it gets boiled down into an instruction to skip over the next n lines conditional on the value of an integer fed to it. QC actually supports two operations: IF and IFNOT. The former skips a number of lines when the integer is non-zero, and the latter them if it equals zero.
When the original QC compiler encountered code like:
if(!my_number)
where my_number is a float in qc, it would actually break it up into two instructions: The first one would apply the logical operator ! to my_number, and store that in a temporary. The second instruction would then feed that temporary to an IF_NOT.
One of the first created QC compilers saw a chance to optimise there, change the IF_NOT to an IF, and skip the ! instruction entirely. This sounds reasonable enough, except that you must not do it for a vector. There is a special operation for applying ! to a vector, which actually applies it to all three components. If you don't use it, then the first component of the vector gets mistaken for a single float, and you get bugs.
In conclusion, the original QC design was perfect and Carmack remains a god. The bug lies in the newer compilers, which should not optimise in the vector case.
Coming up soon is a description of the sequence in which things occur in a frame, which is the reason I was poking about in the source.
#243 posted by JneeraZ [71.70.208.255] on 2009/02/19 22:27:00
Are optimizing compilers really even necessary? I mean, has Quake ever been slow when fed reasonably coded QuakeC?
 Possibly
#244 posted by Preach [86.160.143.42] on 2009/02/19 23:52:12
QC probably used to be a potential bottleneck, back in the day when r_speeds of 800 was considered unacceptable. The engine contains a "profile" command to see the 10 most demanding QC functions, so they were being optimised back in the day. Probably this is where some of the builtin functions come from, like find and findradius, which could be written in pure qc given the earlier builtins.
Nowadays modern limit-pushing maps increase the number of faces by a greater factor than they do number of monsters/entities(most of which are idle and no serious drain anyway). In addition, much of the greater rendering cost gets push onto the graphics card.
So in that sense bad QC is unlikely to cause a framerate drop or anything like that. But there are other limits that have to be fought when it comes to quake. There is a maximum size that a progs file can be, for instance, and compiler optimisations which eliminate duplicated strings in the file have helped large mods compile.
Also, the runaway loop counter in qc is 100000 instructions in a function. If you're coding some kind of loop, then any instructions you can eliminate from the inner loop section are invaluable in avoiding the runaway limit. The findradius builtin mentioned above swaps what would have been a loop through all the entities with a pass through a linked list of the relevant ones.
Of course, there's also some personal satisfaction involved with some optimisation. I've been playing a kind of "programmer's golf" with the ID1 progs, trying to get as few instructions as possible in the monster ai functions like "visible" and "range". At the moment I'm trying to resist writing them directly in assembler to eliminate another temporary variable...they're the best targets for optimisation if you'd like to make a 20,000 monster map support 25,000 instead!
 Tracebox In QC
#245 posted by Preach [81.153.29.95] on 2009/03/07 14:31:16
Nobody asked for it, but here it is anyway: A way to perform a tracebox, similar to traceline but with a full sized object, without engine extensions. Caveats: The emulation of a trace is not perfect; it can throw a false negative in the case where the trace travels through a small but non-zero vertical distance. The test has been designed to prevent false positives. In addition, it's quite expensive in QC operations, although look to the previous post to see whether you should care about that.
"Your mother's a tracer!"
So, the key to being able to trace is, strangely enough, flying monsters. Most of the box-tracing which the engine performs is during physics updates. This makes them unsuitable for testing traces "on-demand", since you have to give control back to the engine first. However, monster movement is performed in discreet steps, moving instantly from one point to another using the walkmove function. Flying monsters have the additional advantage of not being bound to the ground, so we create an entity with FL_MONSTER and FL_FLY set to perform our trace.
The carrot and the stick
It's important to understand exactly what causes a flying monster to change altitude. Every time walkmove is called, the moving monsters decides if it is at the right height, too low, or too high. Accordingly, it attempts to trace a move straight forwards, forwards and up by 8 units, or forwards and down by 8 units. It makes the decision based on the height of its enemy relative to itself. So to control which way our monster goes, we need an enemy entity whose height we can set. This is quite like the carrot on a stick you wave in front of a donkey to guide it onwards, and I shall refer to it as the "carrot". Since our donkey can fly, it will be named "pegasus".
Running the course
The first problem is that we can only climb 8 units at a time. The solution is to call walkmove repeatedly, dividing up the trace up into segments, where each segment has a z component of 8. Since it is unlikely that the trace will have a height exactly divisible by 8, we need to perform an initial run which stops less than 8 units away from the target height, then reset the origin of pegasus so that it lies on the path of the trace, 8 units from the target height. Full marks for whoever spots the tricky boundary case of this method.
Preach's Pro Tip: You can use this trick of calling walkmove more than once to get regular flying monsters to ascend/decend more rapidly!
Jumping the fences
The next problem is what happens when the movement of the pegasus gets blocked. What few people realise about walkmove is that if the trace is blocked, the monster doesn't move at all - I personally imagined it would move the monster as far as it could before being blocked. But if the movement with vertical motion is blocked, the code does attempt a move with no vertical motion before giving up. This could create false positives easily. To make sure that pegasus is properly jumping the hurdles, check that the height of the pegasus changes from one walkmove to the next. This is the simplest test, as it doesn't matter if the trace is going up or down. Of course, you shouldn't do this if the trace is truly flat!
The final straight
A big problem arises if you want a trace which isn't flat, but rises/falls less than 8 units - a shorter distance than a single walkmove. This is the corner case astute readers may have caught earlier. It might be tempting to give yourself a "run-up", to trace from a position behind the desired origin, through the desired start to the finish, so that this extended trace has the right height, and accept the false negatives that the longer trace might cause. The problem is that this might actually cause false positives!
If the pegasus starts within a solid part of the bsp (or possibly other object), then it seems to skip through without colliding. As traces get closer to 0 height, the pegasus takes a longer and longer run-up until it is exceedingly likely it will be outside the level. So instead, the best solution I could come up with for this case is: Increase the height of the pegasus by the desired height, adding it to the maximum height if the trace goes up, and the bottom if the trace goes down. Then perform a horizontal trace. If you look at the 2-D side-on view of the trace, this is effectively taking the rhombus which would be the exact trace, and replacing it with the smallest rectangle which could enclose it.
 Tracebox In QC II
#246 posted by Preach [81.153.29.95] on 2009/03/07 14:35:13
You can lead a horse to water...
Through the steps in the previous post, we've built a reliable tracebox which reports few false positives and no false negatives. So it's time for a little nicety - stopping splash noises. The splash noise occurs when the pegasus crosses a water boundary, but since the pegasus is an imaginary beast, no noise should occur. To avoid it, we test for water by performing a regular traceline from start to end. If trace_inwater i set, then we add 1000 to the height of the trace_start and trace_end, then subtract 1000 from the mins and maxs of the bounding box(thus the box remains in the correct place. Although you could construct a map where a splash would still occur, I think it's unlikely to arise in actual maps.
Photo finish
And that's it. I'm sure I can hear you saying "That's all very well in theory Preach, but it sounds like a bitch to actually implement!" Fear not, for here is a qc file with just such an implementation. In this version, the carrot and pegasus are globally allocated entities, which reduces the overhead of spawning them each time you want to use the function. This could be changed if entities are at more of a premium than function cost.
http://www.btinternet.com/~chapterhonour/tracebox.qc
As a final warning, remember that the trace results are invalid if the tracebox starts outside of the level. When determining this, you have to account for the 3 hull sizes which quake supports. Work out which hull the tracebox fits to, and fit THAT inside the level. This almost always means that you need a player sized space!
 Bloody Hell
#247 posted by Lardarse [62.31.165.111] on 2009/04/20 14:07:52
(You missed a trick with the post icon, btw...)
All we need now is tracetoss, and we have a much more dangerous AI waiting to happen for several monsters...
#248 posted by necros [99.227.133.158] on 2009/04/20 19:59:44
you could try to approximate a toss path with a while loop. maybe in just 25% increments as you don't need a ton of precision.
 Adapting For AI
#249 posted by Preach [86.147.249.85] on 2009/04/20 20:18:35
You can use a similar, but much simpler trick for use with a monster, which would allow it to predict if it can navigate to a certain spot in the future. You again spawn an entity, and we'll call it the pegasus here for ease of comparison. Give the pegasus the same movetype, size and origin as the monster, and make the owner of pegasus the monster.
Then just perform some short distance walkmoves with the pegasus - best to do 4-5 each of a distance around the average walk speed of the monster. Then just see if they succeed or fail. The easiest way is just to see if the walkmoves return true, but you might instead want to test if the pegasus is within a certain distance of a target spot after each step.
You can also substitute walkmove with movetogoal, which attempts to navigate around obstacles. Then the question you're asking is more "will the monster be able to get near the goal if he is given a second to wander about?". I remember using this when coding the scripted death sequence for the final Travail boss, to ensure he could actually walk to a spot where the sequence would make sense(and sneakily teleport him if he was stuck!).
You can actually do this without the need for a proxy entity like the pegasus. Just save the original origin of your monster, and then walkmove it as many times as you need to test whatever it's planning. Once you've decided what the best navigational plan is, reset the monster's origin back to where it started.
(If I have the time tonight, I'll do a little post about making ogres shoot at angles without cheating by changing the overall velocity of the grenades. I'll also put tracetoss for grenades into that.)
#250 posted by Lardarse [62.31.165.111] on 2009/04/20 23:57:52
I was more thinking for fiends, so that they won't jump at you if they can't reach you.
 Ok, Some Thoughts
#251 posted by Preach [86.147.249.85] on 2009/04/21 01:27:05
The way a projectile moves in quake can be described by the increment in it's position and velocity per frame.
1. new_velocity = old_velocity + frametime * '0 0 -800'(assuming that sv_gravity is still 800).
2. new_position = old_position + frametime * new_velocity
(Maths people may recognise this as the Euler method - it's applied to each section separately though)
So if you want to trace a path up until the first contact with something, then you just need something that iterates traceline in this fashion until one collides. Here's me writing a qc function straight onto func:
void tracetoss(vector posa, vector vel, entity ignore, float nomonsters, float inc)
{
local vector posb;
local float startz;
if(inc <= 0)
inc = frametime;
startz = posa_z;
//cut off if it falls too far, like out of level
while(startz - posa_z < 1024)
{
vel = vel + inc * '0 0 -800';//lazy way to do gravity
posb = posa + vel * inc;
traceline(posa, posb, nomonsters, ignore);
if(trace_fraction != 1)
return;
vel = vel + inc * '0 0 -800';
posa = posb + vel * inc;
traceline(posb, posa, nomonsters, ignore);
if(trace_fraction != 1)
return;
}
}
Notice that you can specify the increment you want to use, with the default being the current frametime. Also, the duplicated code inside the loop is somewhere between double buffering and loop unrolling, and is solely for optimizing what could be an intensive loop. The idea is to look at trace_endpos to find where you hit. The maximum height could be made a function parameter, I was trying to keep the function simple.
Similarly, the proper way to do the gravity would be
local vector g;
g = '0 0 -1' * cvar("sv_gravity");
OUTSIDE OF THE LOOP
To make this simulate grenades best, use nomonsters = 2, this makes the trace more generous with collisions in the same way that flymissile does.
"But I didn't want grenades!" I hear you cry. What can we do about fiends? Well, you need to do something similar to this, but using tracebox. Now, the first thing I would recommend is not to just call tracebox as a function, because that might just cause you to exceed the runaway loop counter. Instead you should duplicate the qc-side tracebox code, and incorporate this new loop into that, so that you're only setting the size of the pegasus once, letting it maintain it's origin from one step to the next etc...
The other trick that I would recommend is to pick the time increment you use very carefully. In fact, I'd recommend that you pick the time increment so that at every step the z_difference you require is exactly 8 units, so that it can be done in a single call to walkmove. You have to swap the order that you do things in for that to work:
FIRST trace the new position based on the old velocity(using the old velocity to calculate the timestep)
THEN update the old velocity with gravity based on that timestep.
So the timestep you seek is abs(8 / old_velocity_z). Check for vel_z = 0 if you like. One final thing to remember is that when the sign of old_velocity_z changes from positive to negative (if it does) then you need to move the carrot from being waaaay above the pegasus to waaaay below it!
Now, here comes the gotcha. What do you do once you've performed the trace? If you hit something, you somehow need to decide whether that was the player or the world, and qc-tracebox can't do that (it's hard being a quake monster and therefore entirely blind, isn't it?). You also have to remember your ending position doesn't include the last step of the trace, as that one failed! The best suggestion I can think of right now is:
* Once you have your end position where you hit something, work out how far the player is from you ignoring the z position
* Try to tracebox horizontally towards the player to end up 64 units away from them (using the distance just calculated), again ignoring the z axis.
* Once that tracebox is ended, check if you're within, say 128 units. If so then the jump probably hits. Otherwise it probably misses.
Some of those numbers may need tweaking. I was basing it on the maximum seperation between a touching fiend and player being ~64 units (corner to corner ignoring z axis). Again, you want to trace as close as you can get, without actually colliding with the player, because then the trace fails - like going bust in blackjack. You could also split the horizontal trace into a few smaller steps, which might protect you from going bust.
And I totally ran out of time(and characters) to do anything about ogre aiming. Maybe tomorrow...
 Gremlin
#252 posted by madfox [84.26.168.11] on 2009/05/11 00:20:07
I was trying to add a gremlin to the standard qcc and of course I got a lot of errors.
When I finally had cleaned them up I started the game and reached:
progs.dat system vars have been modified.
progsdefs.h is out of date.
It might sound familiar, but is there a solution?
 Defs.qc
#253 posted by Preach [81.152.234.175] on 2009/05/11 00:37:22
Check the changes you made to defs.qc, you can't add new fields to that file until all of the system fields have been created.
 Typically
#254 posted by ijed [190.20.96.131] on 2009/05/11 01:29:55
It means you've added new stuff too high up - put your changes at the bottom of defs.
 Confirmed
#255 posted by madfox [84.26.168.11] on 2009/05/11 01:36:54
I added four strings to the defs.qc as they were the errors I recived after compiling.
float visible_distance;
.float gorging;
.float stoleweapon;
.entity lastvictim;
How can I make addittions to the defs.qc , or should I delete all functions in grem.qc that work with doe.qc
 Fixable
#256 posted by Preach [81.152.234.175] on 2009/05/11 01:40:10
Like ijed said, just move those lines right to the bottom of defs.qc, and you should be fine.
 Yes!
#257 posted by madfox [84.26.168.11] on 2009/05/11 01:45:47
that worked.
You earned your pronounciationmark back Ij!ed.
Alhough I don't see it steal my gun, it works fine.
 Hit That One
#258 posted by ijed [190.20.96.131] on 2009/05/11 02:04:18
Alot of times. When you're learning blind a molehill is everest.
 !
#259 posted by ijed [190.20.96.131] on 2009/05/11 02:04:46
 Gremlin
#260 posted by madfox [84.26.168.11] on 2009/05/14 11:42:52
Well I trried including a Gremlin in my map without the whole SOA pak. And as I expected was the hipgrem.qc not enough. I had to make a change to the ai.qc and defs.qc as well.
When I was done and could compile without errors the gremlin came in game.
But for some reason the weapon steal trick doesn't seem to go. I did all I thought I need to do changing the needed hipsdef into the normal def.qc but something slipped away.
 Substitute
#261 posted by madfox [84.26.168.11] on 2009/05/14 11:45:33
it was neg!ke with his pronouncion mark.
 Well
#262 posted by madfox [84.26.168.11] on 2009/05/15 21:24:30
i guess its a dubious question asking where the gremlin has left my weapon.
 Bit Masks
#263 posted by necros [99.227.133.158] on 2009/05/24 21:21:36
i want to be sure i understand these:
Operations:
self.flags = self.flags - (self.flags & FL_ONGROUND);
this will subtract FL_ONGROUND but ONLY if FL_ONGROUND is present in self.flags.
whereas:
self.flags = self.flags - FL_SWIM;
would just blindly subtract the flag and risk breaking self.flags if FL_SWIM wasn't there when you subtracted.
likewise:
self.flags = self.flags | FL_ONGROUND;
would add FL_ONGROUND but only if FL_ONGROUND wasn't present in self.flags.
whereas:
self.flags = self.flags + FL_SWIM;
would add the flag as well, but would break if FL_SWIM was already present in self.flags.
Conditionals:
if (self.flags & FL_ONGROUND)
is the only way to check if FL_ONGROUND is present in self.flags.
 Correct
#264 posted by Lardarse [62.31.165.111] on 2009/05/24 23:17:31
But the safe versions are strongly preferred, because they don't break anything.
Note that you can work with multiple bits if you need to. The code for picking up armor removes all 3 armor flags before adding the correct one.
The only operation I'm not sure how to do is to toggle a flag (if off, set it; if on, clear it).
 Toggle
#265 posted by Preach [81.152.238.218] on 2009/05/25 01:35:54
The following code will toggle flags:
self.flags = (self.flags | FL_ONGROUND) - (self.flags & FL_ONGROUND);
The right hand side features two halves. In the case that FL_ONGROUND is already set, the first half does nothing, and the second half is equal to FL_ONGROUND, so the flag gets removed.
In the case that FL_ONGROUND is not set, the first half turns it on, and the second half is equal to zero, so has no effect.
There's a nice kind of symmetry going on with this formula. It combines the adding and subtracting flags, but in such a way that only one actually does anything in each case. The whole right hand side is evaluated before the result is assigned to the left hand side, you there is no risk that self.flags changes mid way through.
It's worth knowing that this can be extended to multiple flags:
float IT_TOP3WEAPONS = IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER | IT_LIGHTNING;
self.items = (self.items | IT_TOP3WEAPONS) - (self.items & IT_TOP3WEAPONS);
This code will toggle the most powerful weapons in the player's inventory correctly, regardless of which ones they may possess. In practice, it would be worth following up that line with a call to W_BestWeapon(), in case the player was using one of the weapons you just toggled.
 Thanks
#266 posted by necros [99.227.133.158] on 2009/05/25 02:12:46
didn't know about the toggle one.
 That Sound Bug
#267 posted by jdhack [75.155.104.195] on 2009/05/25 06:11:24
You know, the one where you pick up 2 items more-or-less simultaneously, and hear only 1 sound. I was thinking of fixing it engine-side, but then I realized this: often, 1 sound overriding another is the desired behavior.
I know of the null.wav being used to kill a playing sound, but I suspect there are other situations. Can you guys give me some examples?
 Upon Further Consideration...
#268 posted by jdhack [75.155.104.195] on 2009/05/25 07:44:34
It probably makes more sense to look at it from the opposite side, ie. when don't you want one sound to override another?
So, picking up multiple, different items; using a key which causes a door to open; what else?
 There's Also The Classic
#269 posted by Lardarse [62.31.165.111] on 2009/05/25 08:33:19
"Quad Cancel" sound bug, where you land just after picking up the quad, and the "oof" overrides the quad pickup sound.
#270 posted by Spirit [213.39.146.110] on 2009/05/25 10:19:55
Picking up the MH at DM4 with no sound (picking up the rockets to achieve that) is a deathmatch tactic.
I am all for it anyways.
 CHAN_VOICE
#271 posted by Preach [81.152.238.218] on 2009/05/25 12:07:23
It makes sense that anything a monster/player says overrides what they were previously saying - for example a pain sound interrupting some other noise.
If people wanted multiple pickups to sound, the fix is easy to perform in QC. Just remove the channel specification from the sound command - if set to 0, the sound plays from any available channel.
 Revised Ruleset
#272 posted by jdhack [75.155.104.195] on 2009/05/26 07:01:27
The DM angle is something I hadn't thought about, so I probably should just apply the fix to sp/coop. I agree that changing the QC is the "proper" way to do it, but an engine workaround has the advantage of not requiring any effort from the user(*).
How about only applying the fix to CHAN_ITEM and the powerups on CHAN_VOICE? Or is there a case where you'd want one of these sfx to be stopped before completion? (I'll probably include a check for null.wav, which would kill all sounds on the channel)
*assuming I do eventually release this, and anyone actually uses it
 Say No
#273 posted by necros [99.227.133.158] on 2009/05/26 09:03:40
to cheap hacks. :(
 No Cheap Hacks?!
#274 posted by jdhack [75.155.104.195] on 2009/05/27 05:32:13
Quake as we know it wouldn't exist without them - interpolation, fullbrights, external textures, skyboxes, fog, extended limits, modified protocols, plus a good chunk of the id & hipnotic code.
It's a good philosophy to keep in mind, but it's never a black-and-white issue. The reality is that all code makes assumptions about the environment in which it's run. And making changes to an existing codebase is never as clean as it would be were the features part of the original design. Sometimes you have to bend the rules to get the result you want. And in the end, if it works, people are willing to overlook the messiness of the implementation.
So I take it personally when someone dismisses my attempt to fix a known bug as a "cheap hack". If you've got any particular concerns or informed criticism, I'd like to hear them. Otherwise, don't bother.
And to those who provided useful input, thank you :)
#275 posted by necros [99.227.133.158] on 2009/05/27 10:19:24
except it is a cheap hack. it will cause an inconsistency in how channels work for a specific few cases which can cause confusion and annoyance later down the line for some poor bastard modder who isn't aware of one guy's attempt to 'fix' behaviour that was working as intended. a sound is expected to override the previous sound playing on a channel.
if it bothers you, fix it in qc (channels 5, 6 and 7 on the player are rarely, if never(?) used-- they could easily be used for a second item channel) because it's a qc bug. you can even play the pickup sounds on the items themselves, although the left/right won't be balanced because the sound isn't emanating from the player, but that solution is probably the most easiest to implement.
 Thank You
#276 posted by jdhack [75.155.104.195] on 2009/05/28 06:16:47
That made a far better case for your point than your previous post ;)
I guess my frustration wasn't really due to you calling it a cheap hack (because I'm not disputing that); it was more the feeling that you were dismissing it outright. The truth is I respect you for all you've contributed to the Quake community, so it's people like you I need to hear from to help me see things from a mapper/modder view. So thanks for the followup.
For me, the annoying thing with a bug like this is, here we are, 13 years later, and the QC hasn't been fixed (afaik; maybe you guys did in Quoth, but that would still leave a few hundred mods that are potentially affected, plus the thousands of maps that people don't run under Quoth).
One part of your post I didn't quite get was the "play the pickup sounds on the items themselves". Were you talking about reworking the QC to call sound() in an item-specific touch function rather than the generic one? Or were you talking about the engine making use of the .noise field?
 In Any Case
#277 posted by Preach [81.152.234.252] on 2009/05/28 09:47:35
I'm not actually convinced that it is a bug, because they added the idea of specifying a channel to qc specifically so that the sounds could be overriden. Perhaps a few sounds should be split off into their own channels, like the landing sound and the item pickup playing seperately. But I can see the sense of not playing multiple "item pickup" sounds on top of each other, because it would create a pretty nasty echo effect. The current system of cutting off and resetting the sound on the same channel is probably easier to parse when you listen.
#278 posted by necros [99.227.133.158] on 2009/05/28 10:39:14
sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); from health_touch()
it plays the sound on 'other' which in this case, is the player who touched it.
if you change this (and the other items) to play the sound on 'self' instead, multiple pickups will all play sounds of the item itself, not the player.
the only problem is that if you pick up items from the side, the sound will not be centered like it is when you play sounds on the player. sounds that the player makes are always centered (they come out of the left and right channels equally).
and no, i didn't fix it in quoth (and i don't think preach did, because i don't remember noticing it when i played quoth2 stuff).
this is really a preference thing, but it never really stood out as something that really needed fixing to me. i never even noticed that it would be a problem because i always took it as a matter of course that multiple items being picked up at once results in blocking some sounds out. it's either that or, as preach mentioned, a cacophony of different pickups all at once which is just as difficult to make out.
also, be wary of using CHAN_AUTO (channel 0) because the engine just picks whatever free channel it can find. that can be the weapon channel sometimes so you'll be in the same spot with say your shotgun blocking out the quad pickup sounds now instead of the nail box. :S
this is just my opinion but i think bringing in cool stuff from more modern engines like doom3 such as proper scripting, proper rotating brushes (the rotating entity itself causes collision without needing to hack in invisible collision brushes) and hierarchical entity binding, all done engine side would be completely bad ass. you will notice i'm am avoiding things like real time lighting, bump mapping and such. to me, as a mapper, i'm less interested in those things than i am with stuff that can increase the creativity of the maps being created.
 Damn Real Life Always Interrupting...
#279 posted by jdhack [75.155.104.195] on 2009/06/01 06:35:41
Anyway, I did look into the rotation stuff a bit. Would the Hexen II code be good enough? Very little change on the engine side, but the collision is quite rough (it just expands the bbox so it's big enough to contain the entity at any angle).
Regardless of the method, the tricky part might be deciding when the enhanced code should be used. Maybe a new SOLID_ or MOVETYPE_ constant? Also, there'd have to be a way to check for engine support via QC, probably via the checkextension system (just checked - DP's DP_SV_ROTATINGBMODEL extension may be the one).
The other features you mentioned sound intriguing, but right now I'm really trying to resist the urge to add new stuff, and just finish what's there (not nearly as much fun...). I'll keep it in mind for the future though.
And you don't need to worry about me adding visual fluff - my GL skills are at about a 1997 level :). Plus, I like my Quake to look like Quake, dammit!
#280 posted by necros [99.227.133.158] on 2009/06/01 07:26:53
mostly the reason i suggested that stuff was because i've yet to see it done so far.
once i got into creating things, i always felt the real impressive thing about doom3 was the script engine but i imagine it's probably many times more difficult to create something like that because it means creating a compiler and interpreting as well as making syntax or whatever that's intelligent.
 Although...
#281 posted by metlslime [24.130.223.174] on 2009/06/01 07:54:26
quake had quakec, which required a syntax, a compiler, and an interpreter, too :)
 Well
#282 posted by necros [99.227.133.158] on 2009/06/01 10:24:05
the big difference here is that it's integrated into the engine and that a map doesn't need to be a mod to implement quite a range of custom scripted events.
but implementing it in a custom engine when no one else has done it (custom engine modifications for scripts) is sort of self defeating because although you may not need a mod to run it, now you need the engine. :S
i should have thought it through before mentioning it, hehe. :P
 Scripting
#283 posted by jdhack [75.155.104.195] on 2009/06/03 06:15:28
Thinking about scripting and metlslime's post reminded me of an idea I posted to the Quoth 2 thread (post 347):
http://www.celephais.net/board/view_thread.php?id=60173&start=347
The examples I gave were silly one-step things, but what I envisioned was a chain of these "operation entities" used to perform a sequence of actions; in essence, a script!
Maybe add some conditional operations (if equal, if greater, etc.), and you'd have some rudimentary scripting ability.
#284 posted by necros [99.227.133.158] on 2009/06/03 10:20:33
purely theoretical discussion at this point but:
what you're describing is essentially what any modder does every time they compile a progs.dat.
stuff like, for example in hipnotic with the sound playing entities or the lightning shooters.
scripting in doom3 renders all those things obsolete. you have your rudimentary entities like func_doors and trigger_multiples for stuff you reuse all the time, but if you wanted to make a lightning trap, you don't need to make a whole new entity.
it's maybe not a big distinction, but i never liked the huge amount of scripting 'entities' that you get in say, hl2. it's many times easier to plan and work on a complex scripted event when you have simple lines of code in front of you instead of 5 trigger relays and half a dozen doors and plats all connected together.
but as i think on it, i feel i'm probably in the minority here. a lot of new guys on doom3world never even touch scripting because it has a steep learning curve.
#285 posted by JneeraZ [24.163.61.78] on 2009/06/03 11:20:10
necros
We evolved the UnrealEngine to use a visual scripting system, Kismet, because we were tired of trying to string together triggers and events for complicated stuff. It really is an archaic way to go these days and makes debugging and absolute nightmare.
 I Never Did Much In D3
#286 posted by bear [94.255.215.125] on 2009/06/03 18:19:48
but the scripting did seem like the most interesting new thing to me as well
 REVIVE!!!!!!!!!!
#287 posted by meTch [69.183.70.109] on 2009/07/14 04:54:32
*godly chorus sings*
i r wins
#288 posted by megaman [94.221.103.25] on 2009/07/16 19:34:21
i see how a visual language makes debugging much easier :)
 Walkmove Returns
#289 posted by Preach [94.169.109.218] on 2009/09/21 21:20:30
So occasionally the navigation of quake monsters is inadequate. Although they walk entirely blind, feeling their way along walls, usually they get blown to pieces too fast for the player to even care. As people who have read through the AI Cafe tutorials will know, the monsters can either walkmove() or movetogoal(). The latter function will hug walls and attempt to navigate a bit if an obstacle is hit. This does take a bit of control of the navigation away from you.
Walkmove is more of a direct command, to move in a direction, to a distance. When a monster is blocked while trying to walkmove, it is worth knowing two things:
1. The monster does not move at all, walkmove is all or nothing.
2. The walkmove function returns FALSE, instead of TRUE.
The return value of the function would be very handy, as if it returns false, your monster would know that it is blocked, and perhaps make a decision based on that (to try and jump, or hide, or strafe from side to side maybe).
The trap here is to go and write a function which replaces ai_run, the usual function which instructs a monster to move towards their enemy. The problem being that ai_run does a lot of other important things for a monster - checking that the enemy is dead, or whether they should start attacking, and so on. You might end up copying the entire function apart from the last line, which you change to the new walkmove code (and reaction to it returning FALSE).
Then if you change ai_run in the future, you need to remember to change your copy of it too. And duplicating code is pretty wasteful too. You might try and refactor ai_run to let you choose the navigation after, but doing that is a lot of fuss.
So a fairly neat solution came to me yesterday, which is why I wrote this whole thing up. Just write a basic function which will move in the correct direction, check the return value, and react if you are stuck. It does not need to replicate the other functions of ai_run(). Then the key trick is to call it from only one of the running frames of your monster. The rest of the frames should all call ai_run() like usual. Every 6 or 8 frames your monster thinks about something else, and the rest of the time it's business as usual.
If you really wanted, you could call ai_run() and your new function from the same frame, splitting the distance to travel between them. If so, think carefully about which function you want to override which. If you would prefer for your monster to attack as normal, put the call to ai_run() last, and vice-versa.
Okay, all told.
 Interesting...
#290 posted by metlslime [173.11.92.50] on 2009/09/21 21:37:49
I ran into this exact situation last night. My solution was to call ai_run(0) every frame, and then call my_walkmove() every frame to do the actual movement.
 Heh
#291 posted by Preach [94.169.109.218] on 2009/09/21 23:52:19
Glad to see I'm at least thinking about problems people care about, even if it's too late to be useful : - p
 That
#292 posted by ijed [190.20.115.237] on 2009/09/22 04:46:01
Gets cogs turning.
Ways to get the fiends more agile.
 Preach:
#293 posted by metlslime [98.248.107.212] on 2009/09/22 10:13:54
there is something maybe you can help with... is there any way to prevent flying enemies from sometimes going inside solid walls?
 It's A Real Mystery
#294 posted by Preach [94.169.109.218] on 2009/09/22 21:45:30
If someone could reliably reproduce it, with a testmap and a 20% or so success rate, then it would be helpful. I'm sure it's just a check that isn't done carefully enough - and it should be really easy to spot because of the isolated nature of the code for flyers. It is something that I've wanted to crack, but I don't know yet...
 I Think
#295 posted by ijed [216.241.20.2] on 2009/09/22 22:40:59
Its to do with navigation by point as opposed to bbox - but flyers and swimmers aren't stuck to the floor in order to move.
Points to a coding can of worms though, if it is that.
 Preach...
#296 posted by metlslime [173.11.92.50] on 2009/09/23 00:31:36
i might, i'm currently testing a flying monster in a room with a large crate in the middle. There was at least one test session where they consistently worked themselves inside the crate, while testing on nightmare mode.
This monster has a custom move function which calls walkmove() and if that returns false, calls movetogoal(). In order to control their vertical movement, I give them a self.enemy that is either 1000 units above them, or 1000 units below them (otherwise they will always seek the same horizontal plane as the player and stay there, which i don't think is very interesting for a flying opponent.)
Anyway, if i can get a reproducible case, I'll let you know.
#297 posted by necros [99.227.133.158] on 2009/09/23 06:46:41
it's not possible to detect if the player is pressing movement buttons is it?
something that would be true if he wasn't pushing any buttons but he was sliding down a slope, for example.
#298 posted by necros [99.227.133.158] on 2009/09/23 09:01:17
i may not need to worry about this after all, i just found out the player's velocity is considered 0 when standing on a platform or whatever and it's moving you.
 Chasing
#299 posted by Preach [94.169.109.218] on 2009/09/23 20:02:32
Is this is the for the same mod where you wanted to create a chasecam? If so, the usual trick is to proxy the player. To do this the actual player entity an invisible movetype_noclip entity, and in playerpostthink, keep resetting the origin to that of the camera entity(to prevent visibility problems). Then through reading the offsets of this dummy player, you should be able to deduce the key presses.
This assumes that you have an entity set up as the chasecam viewpoint, and that you're willing to make a 3rd entity which serves as the visible player. But that is usually acceptable for the kind of mod where you'd want to read the inputs.
 Correction
#300 posted by Preach [94.169.109.218] on 2009/09/23 20:03:05
To do this make the actual player entity an invisible movetype_noclip entity...
#301 posted by necros [99.227.133.158] on 2009/09/23 20:10:34
that sounds interesting, but quite ugly. :P
the only reason i asked was because i was worried that when a player was on a lift it would count as if they are moving, if i checked self.velocity, but as it turned out, if a player is standing on something that's moving, his velocity is 0, so it was all good. :)
 There Is
#302 posted by ijed [216.241.20.2] on 2009/09/23 20:27:12
Kascam - AguirRe was experimenting alot with this. It basically spawns a fake client who goes into a kind of auto spectator mode, either chasecamming or snapping to interesting points from which to watch from a la Resident Evil.
Unplayable from these views, so probably not what you want.
 Special Characters
#303 posted by necros [99.227.133.158] on 2009/09/24 01:56:51
preach, how did you do the progress bar in quoth 2 for the flashlight?
 Character Modification
#304 posted by Preach [94.169.109.218] on 2009/09/24 10:39:42
The bar was made up of 4 characters drawn onto CONCHARS in gfx.wad. The characters we replaced were 4 of the box border characters which are repeated half way down the CONCHARS image. It seems like the engine is consistent in using only the upper row copies.
To add them to a string, the qc used escape characters. FTEQCC (and frikqcc I think) supports specifying a character by number, using the format "/{137}" for character 137. From this, 9 preset strings were created, one for each stage of the progress bar.
The hacky part was getting centerprint to behave exactly as it would for normal messages(so that they would last for 2 seconds regardless of whether the flashlight got toggled during the message). For that, we needed two fields on the player, a float for storing the expiry time of the current message, and a string to store the centerprint message. A global float called centerprintcount was also added.
The centerprint builtin was wrapped to set these two fields to (time + 2) and the string it was sent respectively. It then set the centerprintcount variable to 2. It did no actual centerprinting itself. Instead in playerpostthink the function decided if the centerprint message needed to be changed, asking:
• Has the flashlight been turned on or off?
• Has the charge decreased since last frame?
• Has it been more than 1.8 seconds since we refreshed the flashlight?
• Is centerprintcount greater than zero?
• Has the centerprint time expired for the player's message?
If the last condition was true, the player's centerprint message was changed to "". Then if any of these conditions are true, a new centerprint is sent. It would take advantage of the fact that calling the builtin centerprint with two strings will see them printed one after another(in fact it can be overloaded with up to 8 strings, the maximum number of parameters a quake function can carry). The correct string for the flashlight(including no string if it has turned off) would be retrieved and set along with it.
The last detail is that centerprintcount is decreased by 1 in startframe. This works to ensure that every client will get centerprint messages updated correctly. There is actually a bit of oversend when it comes to sending these messages - when ANY client gets a centerprint, everyone gets theirs updated. Similarly if the centerprint is triggered in a playerprethink or player physics event it will get re-sent in the next frame. But this only raises additional network traffic on a few frames, the important thing is to avoid spamming the message every frame.
An alternative method would be to build a centerprint message byte by byte, the way that temporary entities for lightning or gunfire are created. Set msg_entity to the player, send an SVC_BYTE(MSG_ONE, SVC_CENTERPRINT) - SVC_CENTERPRINT can be looked up in the source. Then send the bytes corresponding to the characters making up the progress bar, followed by a SVC_STRING of the centerprint message.
Advantage: you can pick the characters to send procedurally, avoiding the hard coded strings. If you added more characters to your set, you could have sub-character progress marks.
Disadvantage: you can only send one string, because it is null terminated, which ends the centerprint. Although the quoth method I described only supports one string per centerprint, it is possible to see how it could be expanded by adding more centerprint string storage to each player, and sending all the strings.
#305 posted by necros [99.227.133.158] on 2009/09/24 21:36:02
impressive, thanks for the info :)
wouldn't it have been easier to assemble the string with code instead of making presets?
like:
a = "["
b = "="
c = "-"
d = "]"
then just doing string = a + b + b + c + d? or does that not work in qc? i've never worked with strings much in qc.
 Append
#306 posted by necros [99.227.133.158] on 2009/09/24 22:49:01
just got a chance to check and i realised that string manip isn't possible in qc :P
 String Manip
#307 posted by Preach [94.169.109.218] on 2009/09/25 01:15:50
That's why you need the trick which lets you write bytes, it's heavily practised in Prydon Gate with all those text menus. frikqcc introduced a handy addition as I recall, making it so that a single quoted character whould be translated to the numeric byte value you need for writebyte. So if you had a function
print4(float a, float b, float c, float d)
which prints the bytes a,b,c and d, you could call it as
print4('n','a','i','l');
which makes the code a bit more readable.
Now I'm gonna go away and think about the best way to formalise faked strings like that...
#308 posted by necros [99.227.133.158] on 2009/09/27 04:59:25
i've got an interesting problem...
ftos(). a great feature about this stupid thing is that it seems to store the converted string into the same place in memory, so if you use the centerprint trick that concatenates strings, and you were to put multiple ftos() into it, it would print only the last ftos() that was called.
to get around this, i tried making a bunch of temp strings, and then setting each of these temp strings with ftos() before calling the centerprint, but that doesn't work because, it seems, the temp strings are only a pointer to the memory location that ftos() is using, so the end result is absolutely the same.
is there anything i can do?
 Depends
#309 posted by Lardarse [62.31.162.25] on 2009/09/27 11:26:38
What's the numbers that you need to centerprint?
If it's just 2 numbers that are a few digits long then you can convert one of them to strings that are a digit long and then print the other one after it.
Example here (with the functions DigitToChar and NumToString, you may want to use the search function as they're near the bottom of a long file): http://svn.quakedev.com/viewvc.cgi/rquake/trunk/source/rjs.qc?revision=68&view=markup
#310 posted by Lardarse [62.31.162.25] on 2009/09/27 11:33:08
Except that instead of strcatting the digit strings together, you print them one by one.
Please excuse the evile QCCXness that that code had back then...
(We need a barf icon...)
 Stream Of Conciousness
#311 posted by Preach [94.169.109.218] on 2009/09/27 12:24:43
When it comes to functions like dprint and sprint, the usual trick is to call the print function after each ftos call, to flush the buffered string into the console, eg:
dprint("health: ");
s = ftos(self.health)
dprint(s);
dprint(", height:");
s = ftos(self.origin_z)
dprint(s);
dprint("\n");
This works fine with prints to the console, as the messages are cumulative, written one after the next. The problem with centerprint is that each call flushes whatever was previously printed, so you need to get everything into one message.
This of course leads us down the road of byte by byte messages, where you construct a function which can convert a float to a sequence of characters, which are then sent by SVC_BYTE. So it's possible, just not pleasant.
I've been trying to think of a way to write a "library" which would make writing this kind of centerprint byte by byte more straightforward. I think the best structure would be:
• A buffer of 16(?) floats, enough to store one line-width of a centerprint message
• A function called Flush() which sends all 16 characters in the buffer with SVC_BYTE.
• The concept of a function object called a stream.
• Customisable functions can then be written which read values from streams into the line buffer.
It would be at the last level that layout could be controlled by the coder - deciding what to do if a stream is longer than the current line, whether you need to render a border on the first and last character, etc. The library would come with some examples.
The important idea is the stream. This would be a dummy object with .think set. What you set think to depends on the content of the stream, but the simplest example of a constant string would look very much like a monster animation function. For example, the sequence "hello, world" would begin:
helloworld_1 = ['h', helloworld_2 ] {};
helloworld_2 = ['e', helloworld_3 ] {};
helloworld_3 = ['l', helloworld_4 ] {};
Then reading a character from the stream self is performed by the lines
self.think();
char = self.frame;
(you need to make whatever is thinking self, that's the normal quake rules)
The advantage of this method is that then you can invent a new function which, for example, streams the digits of a float to some precision. As long as you make the interface the same - use .think() to advance the stream a character and .frame to access the current character - then the higher level functions can handle it identically.
It would probably be helpful to add one property to the stream entity: length. That way, the highest level of function can see if a stream will fit on the current line, and if not then consider moving it to the next line. It would also be easy to wrap streams around lines, simply output as much as will fit the current line, flush, then pass the partially completed stream to the next line.
You can also imagine a stream modifier, an entity which could when queried would read a second stream entity, and then either pass on the character it read, or skip that character and go to the next one - stripping out white space perhaps.
 And One More Thing
#312 posted by Preach [94.169.109.218] on 2009/09/27 12:28:07
If you only need three values, and it's ok to print them out one after another, you could use vtos() on a specially constructed vector, with the three values set to _x, _y and _z of the function. A little easier than overengineering stringstream for quake...
 Wait... What?
#313 posted by necros [99.227.133.158] on 2009/10/04 02:51:37
two questions,
1. is the engine hard-coded to give players the axe and shotgun when they first load up a map?
2. (and this is the weirder one) if parm1-16 are global variables, how is it in COOP with more than 1 player, they can retain items and such. are parms special variables that have extra copies for each player? how does the engine know which player's parms we're talking about then?
#314 posted by necros [99.227.133.158] on 2009/10/04 02:56:57
scratch the first question, i did something dumb which made it seem that way.
 A Parm And A Weave
#315 posted by Preach [94.169.109.218] on 2009/10/04 13:30:10
The engine stored parms for each player internally. I believe the way it works is that the QC globals parm1-16 are set to the values the engine saved just before it calls PutClientInServer() for that player. So the parms are only valid to read in coop for the duration of that function (and any functions it calls). Otherwise you will probably be reading the parms of the last client on the list.
If you're removing the axe from the player, make sure you handle the case where he runs out of ammo with all weapons - in the standard code it will switch to axe without checking if you have one.
#316 posted by necros [99.227.133.158] on 2009/10/04 20:01:10
great, thanks for the info. :)
#317 posted by necros [99.227.133.158] on 2009/10/26 03:36:41
this one's more of a math problem...
how can i align monsters with the ground plane underneath their bodies? is it even possible? vectoangles only ever sets x and y, never z, so a full parallel alignment seems impossible.
 Something Along The Lines Of
#318 posted by Lardarse [62.31.162.25] on 2009/10/26 07:29:37
Trace directly downwards, and compare trace_plane_normal to the vertical, then derive the angles needed from that.
You probably need 2 calls to vectoangles, with things swapping around between calls.
 Algorithm
#319 posted by Preach [94.192.82.29] on 2009/10/26 10:47:00
This is roughly what I'd do, not properly converted into qc:
//yaw is the desired facing of the monster
mapAnglesToFloor(entity mon, float yaw) =
{
//do the trace and exit early in easy cases
traceline down
if(trace_fraction == 1 || trace_plane_normal == '0 0 1')
return '0 yaw 0'
//construct a vector perpendicular to both the desired facing of the monster and the normal from the ground, by using v_left
makevectors('0 yaw 0');
//get the actual facing out vector using the cross product
facingvec = crossproduct(v_right, trace_plane_normal);
return vectoangles(facingvec);
}
I'm not sure it actually addresses your concerns about ang_z not being set though. It is also possible that I have the handedness of the coordinate system wrong, and so you need -1*v_right for it to work.
You also might want to consider interpolation of some sort so that the monster doesn't go crazy on broken ground or trisoup terrain. In that case, it is probably best to have a field storing the old "normal", then calculate a new one with
normal = normalise(normal + trace_plane_normal);
You could scale one of the vectors to cause slower or faster interpolation. By interpolating the normal vector, you can be sure that the changes in facing by the monster are responded to directly.
 So
#320 posted by ijed [216.241.20.2] on 2010/03/16 19:43:38
I've got a point entity called a func_door_model. The idea is for the mapper to specify a .bso model in there and circumnavigate a load of issues - breaking max models, patchy lighting, messing around with texture alignment etc.
It seems to work pretty well, the whole idea is to later on extend it to other entities like trains, breakables and so on.
The first problem (of many) is that doors created this way aren't generating their trigger field.
What I have is a 'wrapper' piece of code that specifies a .mdl and replaces the model field with that value - this is a an engine fix for DP that I imported from elsewhere.
As I understand it:
cmins = self.mins;
cmaxs = self.maxs;
and
self.owner.trigger_field = spawn_field(cmins, cmaxs);
Are what create the trigger field, but the first one isn't working when an external .bsp is referenced.
I can touch the door and fire it from a trigger, so the functionality is intact apart from the trigger.
Any ideas?
 Relativity
#321 posted by Preach [94.171.242.186] on 2010/03/16 21:41:35
If you placed your func_door_model at the origin, then I expect that the trigger field would work perfectly. If you enjoy a challenge then work from that hint and ignore the rest of the post...
Otherwise, I'm hoping that the following is the fix to your problem: The assumption that the trigger field works code works on is that the entity is placed on the origin of the map. This is always true for baked-in models like a standard func_door.
For example, if you built a 64x64x64 func_door with a corner closest to the origin at '512 512 0', then door.mins = '512 512 0', door.maxs = '576 576 64' and door.origin = '0 0 0'. It's a bit strange to think about at first, because regular entities like players or monsters tend to have the origin half way between the mins and maxs. (*)
Luckily, this makes the fix very simple, and backwards compatible with a regular func_door.
cmins = self.mins + self.origin;
cmaxs = self.maxs + self.origin;
This should work with regular .mdl files too, although you'll run into another problem with them which is much harder to work around. You could also try swapping self.mins + self.origin with self.absmin, not sure if it's any better for compatibility with dp though.
(*) There is an uncommon exception to this rule, found in rotating entities. Since models can only rotate about a single axis - the origin - the bsp compiler has to play some games with them. It finds the origin of the info_rotate for the model, then moves the brushes of the model so that the origin of the map lines up with that spot.
Once it has compiled that model, it sets the origin value of the entity with the model to equal the origin of the info_rotate - thereby reversing the movement and restoring the original location of the entity. Of course, the lighting and texture alignment are likely shot to hell, but who cares!
 Hm
#322 posted by ijed [190.20.81.89] on 2010/03/16 22:36:12
You're the man.
Challenge is good but the first paragraph was a bit cryptic - I had to read the rest to get the bit about it being the world origin.
Makes perfect sense though, and the added bonus of true .mdl doors is interesting...
I've wondered about why the rotating mesh was moved to the center of the world, but docs there aren't much of.
In any case, this puts me well on the way - also going to try some stuff with trigger_once_bbox working in a similar way, the mapper setting the size of the trigger numerically.
Am I right in thinking you did something similar in Quoth2?
 Just
#323 posted by ijed [190.20.81.89] on 2010/03/16 22:37:10
Don't tell me how you did if you did - there has to be some challenge :)
 Some Bits
#324 posted by Preach [94.171.242.186] on 2010/03/16 23:04:14
We had the model-saving bounding boxes on triggers and external bsp format models. We don't have .mdl format doors yet, there's a little wrinkle with solid types which I don't think can be fixed nicely.
We also didn't fix the bug from #320 in quoth yet, although I expect it'll be in the next release... As a workaround, I suppose people will have to add the door trigger manually.
 MOVETYPE_PUSH Not Bsp
#325 posted by ijed [190.20.81.89] on 2010/03/16 23:11:27
Yeah, got that one. It also seems to do something strange to the bbox - I've seen this before where the size isn't what'd be expected.
I imagine that can be fixed by changing the movetype and putting an invisible helper in there - that's similar to our pushable solution.
 Can Anyone Confirm?
#326 posted by necros [99.227.131.204] on 2010/04/07 06:33:57
if i set .nextthink = time + 0.001 (or any very very small number), that should guarantee it will be called on the next frame, right?
 Almost Surely
#327 posted by Preach [94.171.242.186] on 2010/04/07 12:29:58
Most of the time that will be fine. Most engines enforces a 72 fps limit on physics, because once you get into higher framerates you start to see physics glitches. I assume these arise because of floating-point errors once you start evaluating collisions with increments that small. If you want to see it, try increasing the max_fps in fitzquake to the 300-400 range before riding on a lift (I may have remembered the command wrong, but there is one that lets you change it server side).
One circumstance where you might have a problem is if someone sets host_framerate very low to create a slow motion effect. It's not too much of a concern though, because it is someone messing with console variables, and you can't always prevent people breaking stuff if they use em.
However, there's an even simpler way: set .nextthink = time, or even .nextthink = 0.01.
I used to think that quake ran think functions if the following inequality held
time - frametime < .nextthink <= time
But actually, the left hand inequality does not exist. From the engine source:
thinktime = ent->v.nextthink;
if (thinktime <= 0 || thinktime > sv.time + host_frametime)
return true;
if (thinktime < sv.time)
thinktime = sv.time;
ent->v.nextthink = 0;
The engine resets nextthink to zero every time it calls a think function, and so ignores think functions only if nextthink is in the future or <=0. You should be able to get things to run every frame just by setting nextthink to something <=time.
There's an interesting additional bit of info to be gained from this section of the engine code. We see that the QC value time is set by the following line
pr_global_struct->time = thinktime;
The previously quoted source code set thinktime from the entity's original .nextthink value. So during the QC think function, time is always reported to be the moment that the entity intended to think, rather than the server time at the end of the currently processing frame. The one caveat is that time is bounded below by sv.time, so if we set self.nextthink = 0.01, we won't suddenly be miles back in the past when think is called.
Some of that explanation might be a bit garbled, I was figuring it out myself as I went. So maybe this timeline will help
We assume that at this time the server is running at 50fps.
sv.time
This is the "old time", the first point in time not processed in the last frame. Time is set to this value for the following things:
StartFrame, think functions for .nextthink <= sv.time.
sv.time + delta
As long as delta < 0.02, then the think for that entity must occur in this frame. Time is set to this value for the following things:
think functions for
sv.time < .nextthink < sv.time + 0.02
sv.time + 0.02
Anything with a think greater or equal to this is ignored, it will happen in the next frame instead.
In conclusion, I'd go with self.nextthink = 0.01, because time will be set to sv.time anyway. I've not tested if there are any side effects of that though. self.nextthink = time should also work and might look less weird.
 Thinking Without Thinking
#328 posted by Lardarse [62.31.162.25] on 2010/04/07 14:40:43
Personally, I prefer self.nextthink = time; although feel free to follow it with // Next frame if you want your code to be understood by others.
And note that the code checking for .nextthink being non-zero means that the think function is only run once (unless .nextthink is reset). But setting it to 0 will cause it to stop thinking. Which is what causes the statue bug in id1.
Reading that through has taught me something, though. Namely that time is relative during a think function.
I do have one question, though: What happens first: think or touch?
#329 posted by necros [99.227.131.204] on 2010/04/07 19:34:28
thanks, preach. as always, very informative!
while you're here, could you tell me if i understand .ltime correctly?
it seems to basically be time, except it only counts up when a bsp model is moving.
i believe it only works when the solid is SOLID_BSP or if the movetype is MOVETYPE_PUSH.
when it stops moving (comes to rest OR is blocked), the timer stops. this is how calcmove can work with a static nextthink even if a door or train gets blocked.
 Oh, Yeah
#330 posted by Preach [94.171.242.186] on 2010/04/07 21:28:31
I should have mentioned straight off that the rules are different if the entity is MOVETYPE_PUSH. But it's worth looking at, because it also lets us explore how physics timing relates to this new QC-think timing.
You are right about how ltime works, it's "local time" for the MOVETYPE_PUSH entity. It advances at the same rate as the normal clock except if
a) The entity is blocked, in which case time is not advanced
or
b) The entity's .nextthink will occur before .ltime + host_frametime(within this frame) in which case ltime is increased only as far as .nextthink (bounded below by 0)
The latter case is important because when ltime only advances by as much time as it needs to equal nextthink, the physics run on the entity this frame are calculated so that it only travels for this amount of time, rather than for the full length of the frame.
I should add that again, this is only applied to MOVETYPE_PUSH entities. Other entities always move for the entire length of the frame, host_frametime. There is also a strange kind of time travel which can affect these entities. Think functions are calculated first, and when they are called the QC variable time might be anywhere between sv.time and sv.time + host_frametime, depending on the exact value of .nextthink. Once the think is resolved they will get moved, but if they collide then the QC time is always set back to sv.time for the .touch functions.
As a final thought, it is worth remembering that entities in quake are processed by the physics engine in sequential order, and setting the QC time variable does not interpolate any entities between their positions at the start and end of the frame. All the entities before the current entity will be at their end of frame position*. All entities afterwards will likewise be in the position they occupied at the end of last frame. Knowing how the QC time variable is set is only of interest to resolve seeming paradoxes where you are sure two events occur in the same frame, but the QC reports different times for them.
* Ok, this might not be their final position, because something might collide with them or teleport them in QC or something. But in terms of their own physics, they are done for the frame, no more moving or thinking.
 Clarification
#331 posted by Preach [94.171.242.186] on 2010/04/07 22:20:23
b) should really have read:
"The entity's .nextthink is less than .ltime + host_frametime(before the time at the end of the frame) in which case ltime is increased only as far as .nextthink (bounded below by 0) "
This would make it clear that ltime does not advance when nextthink <= ltime.
 Back To Ltime
#332 posted by necros [99.227.131.204] on 2010/04/10 00:20:02
is there any reason why ltime would run slower than normal time?
i can't really explain it better than that, other than when i watch both ltime and time displayed next to each other (for example, bprinting both every frame), ltime counts up at a slower rate.
 Imprecision
#333 posted by Preach [94.171.242.186] on 2010/04/10 00:28:18
Only thing I can see which might account for it is that sv.time and host_frametime are both double-precision floats. Since ltime is stored in a QC field it only retains the precision of a regular float. In fact, the increment gets cast to a single-precision float before it's added to the single-precision ltime value. So my guess would be that it's a byproduct of the lower level of precision in that calculation.
#334 posted by necros [99.227.131.204] on 2010/04/10 01:30:05
i tested a bit more and slow frametimes seem to slow it down a lot? o.0
if i set fitzquake's maxfps to 10, it counts extremely slowly. i don't really understand what's going on here.
 Sorry Lardarse
#335 posted by Preach [94.171.242.186] on 2010/04/10 02:33:45
I do have one question, though: What happens first: think or touch?
I totally missed this question first time round, here goes:
For a player:
PlayerPreThink always comes first.
Next is the .think function (for frame animation etc)
Then comes whatever kind of physics the player has, so if there's a collision .touch happens now
Finally PlayerPostThink is run.
If it's a MOVETYPE_BSP, it moves first (and so any .touch and .blocked calls occur), and then calls .think functions after that*.
MOVETYPE_NONE won't create collisions by itself, so it only runs .think. It's worth considering that a MOVETYPE_NONE can still be involved in collisions, and in that case the .touch may be called before or after the think, depending on whether the colliding entity is before or after this one in the list. The same is true for any entity when they are the second party in the collisions.
MOVETYPE_NOCLIP doesn't generate collsions either, it's just .think when it comes to processing.
MOVETYPE_STEP is for monsters, and they have a weird order. If they're free-falling from a jump, then that gets processed first, and any collision there produces a touch before the think. However, most of the time monsters only move during think functions. One of the two navigation builtins are called in the think, which hands control back to the engine for physics to be run on the "step". If it collides, then the touch gets called on top. So the think will begin before any touch, and finish after the touch!
Finally, all the other "projectile" movetypes run .think before moving, and thereby having a chance to .touch anything.
In conclusion, it's a mess! The entity might always be the "other" entity in a collision, so you can't really say concrete stuff about whether the touch will happen before or after a chance to think. I think the list here is still useful though, for knowing when the physics runs. This means you can always be aware of whether an entity has already moved or not while in a think function.
*There is an argument here for rewriting the hipnotic rotator code here. If you make a function which is called from StartFrame which loops through all the blocker entities and sets velocities for them, you have changed their velocity before physics runs on them, so they'll move into place this frame. The current code sets it in the think, which means they're always lagging behind the target for a frame. You would also be able to set .nextthink to (.ltime + framtime * 0.5), and use a doubled velocity to ensure exact motion.
#336 posted by necros [99.227.131.204] on 2010/04/21 02:54:22
a little bit more on SOLID_BSP and .velocity
a SOLID_BSP entity won't move unless it's .nextthink is non-zero. it doesn't matter what it's set to, although, obviously if it's less than ltime, it will be set to 0, just as long as it's set. if you set .velocity without setting .nextthink, no movement occurs (although the entity retains .velocity setting).
 Preach, Re: 332
#337 posted by necros [99.227.131.204] on 2010/04/21 06:09:30
preach, could you correct me if i'm wrong?
in post 332, i mention that time seems to more slower on ltime than real time.
say, on your bsp entity, you set:
self.nextthink = self.ltime + 0.01;
to loop a function over and over via .think.
if your framerate was really low, like 10fps. according to what you said above: The entity's .nextthink will occur before .ltime + host_frametime(within this frame) in which case ltime is increased only as far as .nextthink
if time = 0.
one frame goes by at 10fps:
if your nextthink is 0.01, but you are getting 10fps, then .ltime will be set to 0.01 even though real time = 0.1
we get ready for the next frame and set self.nextthink = self.ltime + 0.01; //next frame
.nextthink is 0.02 now.
now more frame at 10fps:
time is 0.2, but .ltime wil only be 0.02.
and so on and so forth.
ltime is only incrementing by 0.01, even though actual time is incrementing by 0.1.
am i getting this right?
 Yup
#338 posted by Preach [94.171.242.186] on 2010/04/21 10:05:33
Yeah, that's right. Remember it will also only move for 0.01 seconds per frame, so you need to set its velocity carefully if you are relying on velocity for motion.
#339 posted by necros [99.227.131.204] on 2010/04/21 21:26:56
i made accelerating/decelerating movers but i couldn't find an acceptable way to make them accurate.
from what i have seen, it seems the only way to make it 100% accurate would be to externally set velocity via a helper entity. unfortunately, this would nullify the point of .blocked and ltime as a blocked mover wouldn't pause and would risk becoming out of sync.
as such, i've just left the acceleration with ltime and accepted the inaccuracy. it unfortunately means if you are getting really bad frame rate 10-20fps, you will see a marked increase in time for movers to complete their movements.
otoh, maybe if i accepted a lower precision by setting nextthink to ltime + 0.1 (use slower refreshes), it would decrease the disparity between time and ltime...
i'll have to see how that works out i guess. :S
 Accellerated Progress
#340 posted by Preach [94.171.242.186] on 2010/04/21 23:04:51
I think that there is a way to overcome these difficulties without a helper entity, so long as you're happy with a bit of not-really-calculus behind the scenes. You can get a version with one frame lag just by using a few entity fields to store some floats(and the one frame lag could be eliminated using the trick mentioned a few posts above of pushing updates to a mover's velocity during startframe, in order to occur before physics).
The key is to increment one of the variables by frametime in every frame which you are blocked. I'm writing out the details in my notebook currently, but it's the kind of thing that would really be best served with an external page full of diagrams and equation notation rather than a hurried post on this board. Perhaps even some genuine, complete QC code to prove I'm not chatting out my arse. Watch this space...
 Lol
#341 posted by necros [99.227.131.204] on 2010/04/21 23:46:49
well, i will definitely want to see what you are talking about, but bear in mind i'm not that much of a mathematician, so if it's as complicated as you are implying, i probably won't do it. ^_^;;
 Running Dry
#342 posted by madfox [84.26.170.230] on 2010/04/26 04:54:39
Hey Preach, did you receive my email?
I'm rather stuck in the monster toppic.
 Hmm
#343 posted by Preach [94.171.242.186] on 2010/04/26 10:34:59
Send it again, don't think I have it.
#344 posted by madfox [84.26.170.230] on 2010/04/26 21:29:05
#345 posted by necros [99.227.131.204] on 2010/05/11 04:37:26
.huntt_ime
Set to time + something when the player is in sight, but movement straight for
him is blocked. This causes the monster to use wall following code for
movement direction instead of sighting on the player. (sic)
in ai.qc
is this true? it sounds like a lie. :P
 The Hunt Is Over
#346 posted by Preach [94.171.242.186] on 2010/05/16 16:37:21
The only instance of "hunt_time" in the qc source is in the comment about ideal_yaw. I'm guessing it's something they used to do in ai_run. It may have been taken out because movetogoal tries the direct path to the enemy before using the wall following code. This would suppose that originally the function would call walkmove if hunt_time wasn't set, set hunt_time if walkmove returned false, and called movetogoal while hunt_time was active.
#347 posted by necros [99.227.131.204] on 2010/05/16 21:05:02
ah that would make sense.
one thing i noticed about the movetogoal code...
it always seemed to me that doom had much better wall following code. quake monsters often get caught in areas when trying to path to the player, but doom monsters quite often turn up in surprising places especially if you watch them in the automap. quake AI seems to 'give up' wall following very early, usually before the wall following has a chance to get around a particular corner or whatever.
mm, that was random. :P
 Well Then
#348 posted by meTch [64.148.30.122] on 2010/05/17 01:44:31
we should just see how D00M does it,
and port it to,
(_)uake :D
.|
 Monster Only Clip...
#349 posted by necros [99.227.131.204] on 2010/05/31 21:35:41
i wonder if it would be feasible to take the func_togglewall and do this:
rename it to func_monsterclip
make it non-solid
movetogoal -> movetogoal_builtin
and then we make a new movetogoal that loops through all func_monsterclips, makes them solid, called the movetogoal_builtin and then afterwards, makes all the func_monsterclips nonsolid again.
#350 posted by necros [99.227.131.204] on 2010/05/31 21:59:19
ran a little test.
instead of a generic monsterclip, i created a method to get larger bbox monsters to move correctly.
you essentially build your 'hull3' out of brushes and turn the entire thing into a single func_clipModel, and then you tie that clipModel to the monster you want to run collision with via clipModel->targetname editor key fields.
this could actually work because it won't impede smaller bbox monsters (that can use normal hull1/2 collision) since the clipModel is only every solid during that single monster's walk frame...
 Necros:
#351 posted by metlslime [67.188.81.46] on 2010/06/01 00:35:07
Nice, I'd really like to see some larger monsters or bosses/minibosses (that can actually move) in quake. This could be a piece of that puzzle.
#352 posted by necros [99.227.131.204] on 2010/06/01 01:06:00
yeah, works pretty decent, but of course it imposes some limitations.
you need to 'clip' any area where the monster will be, of course, and that means you have to visualize the hull expansion yourself and implement it.
also, currently how i do it is to use the same method that hipnotic did for the func_togglewall and that is to just add '8000 8000 8000' to the origin when you want to turn it off, and then subtract the same vector when you want it on.
i don't know how big a deal it is if you had a generic monsterclip entity that EVERY monster in the map would have to toggle back and forth every animation frame. that could be pretty brutal.
it's probably better to somehow localize monster clips so only the monsters most likely to actually touch them will be toggling them (hence why i opted for a clipModel->targetname method instead of just putting it in walkmove and movetogoal). (large bbox monsters use a special wrapper for ai_walk and ai_run).
 Some Problems
#353 posted by necros [99.227.131.204] on 2010/06/01 01:33:09
quake seems to use start the hull2 bbox from the bottom left (mins) of the monster.
this means that if you use a bbox of size (for example) '-128 -128 -24' - '128 128 64' only the mins up to '-64 -64 64' is used when checking collision.
i thought that quake would start the hull2 size from the center of the monster, but this is not the case.
this creates a problem now because collision is still messed up.
if we resize the monster to hull2, call movetogoal and resize back to the new hull size, collision against the world (and func_clipModels) is fine, but the monster is now able to walk inside the player and other monsters.
i'll have to put more thought into this, i guess...
#354 posted by metlslime [166.205.137.59] on 2010/06/01 02:59:10
Wait, how do shub and chthon work? They have large (stationery) bboxes and players seem to collide against them correctly.
#355 posted by necros [99.227.131.204] on 2010/06/01 03:12:01
yeah, the collision of other bboxes is fine.
it's the collision against the world that is messed up.
and that's the big problem:
movetogoal will function correctly vs other bboxes if you set the bbox correctly. 256x256x128 or whatever.
movetogoal will function incorrectly vs world when bbox is set to 256x256x128.
if you set bbox to standard hull2 size before movetogoal and reset to 256x256x128 after, monster will move inside player.
what i've done so far is left the bbox at 256x256x128 and simply 'offset' the func_clipModel so that sides that the mins hits are smaller than sides that the maxs hits.
kind of hard to explain, when i figure everything out, i'll probably make a blog post about it with pictures to explain it properly.
also, another interesting (and annoying) side effect: because of the way the standard ai_run code is sandwiched between func_clipModel toggles such that the clipModel is active when ai_run is called, things like the visible() function fail if the player is inside the clipModel since visible uses a traceline to determine if the monster can see it (and since the clipModel is solid during that period, the trace hits the clipModel and determines the player is not visible).
 Append
#356 posted by necros [99.227.131.204] on 2010/06/01 03:16:11
another way to look at it is this:
for the purpose of bbox vs world, only the first hull2 coordinates starting at the mins are solid.
that is to say:
if the bbox was mins: -128 -128 -24, maxs: 128 128 64
world collision is done from -128 -128 -24 to -64 -64 64 (mins + VEC_HULL2_SIZE)
because VEC_HULL2_SIZE = 64 64 88
 Oh I See...
#357 posted by metlslime [67.188.81.46] on 2010/06/01 07:21:30
if you set the bbox down to standard hull2 size, it's collision against other entities is wrong. If you leave the bbox alone, its collision box is offset from the correct location.
Two ideas:
1. before moving the oversized entity, make ALL other solid entities (or at least all entities within a findradius) larger by XYZ amount, to compensate.
2. have two entities, one oversize and one normal size, and move them both. If either one is blocked, set both entities to the location of the blocked entity.
Not sure if either of these are completely workable.
#358 posted by necros [99.227.131.204] on 2010/06/01 08:12:49
1. could work, except it's just (potentially) a lot of entities to enlarge.
2. this is better, but the problem is that if one is blocked, and we reset the position, nothing happens for that frame and likely movetogoal will try the same thing next frame.
currently what i've done is use bboxes on all the func_clipModels. this means each brush needs to be a seperate entity and we can't have sloped/angled faces anymore (since everything is just a box now).
it works and doesn't seem too slow, but we loose a bit of brush flexibility since we can't have any angles any more. of course, you're really just blocking out the area, so this could actually work. i'll leave it this way for now and test it out for now.
 I'm Not Compensating. Really!
#359 posted by necros [99.227.131.204] on 2010/06/10 22:31:26
http://necros.quaddicted.com/temp/dragon.jpg
the collision stuff has been working well without any further problems so far.
the really nice thing about it is that for monstrously large monsters like the dragon in that shot where you don't necessarily want the bbox to completely cover the entire model, all you have to do is expand the clipModel entities out further from the actual walls.
#360 posted by negke [88.70.250.215] on 2010/06/10 22:36:16
Is that the DOE dragon?
 Yeah
#361 posted by necros [99.227.131.204] on 2010/06/10 22:38:15
i rerigged him and animated him for actual combat and not just flying around path corners.
 Accelerating Back
#362 posted by Preach [77.98.129.22] on 2010/06/18 00:53:17
So I've just spent about a month without internet at home, shame I missed all that stuff about large bboxes, because that's a cool idea. If you're doing a landbound monster with a tall box, then you can create maps which can be bbox-blocked with greater ease. Low walls rarely need to be boxed in this case, just obstructions which are above the head height of regular sized entities but low enough for "the boss" to collide with.
Anyway, that's a digression. In my time away, I had lots of time to get on and finish projects. A fair few of them were quake related, and I'm posting the first one now. It's the tutorial I mentioned a dozen posts up about accelerating MOVETYPE_PUSH objects. Since it involves some formulae which I've done up in LaTeX and a few graphs, I've made a web page for it rather than just copy-paste it straight onto func.
Accelerating pushers
Also means I can fix typos and other problems, so post them here!
#363 posted by necros [99.227.131.204] on 2010/06/18 01:08:25
i haven't really read your above post yet as accelerating movers isn't a pressing issue anymore, but i just wanted to mention: you should compile all your coding tips you've made in this thread and put them up on a site somewhere. some of them are quite useful and others are downright golden.
 No Longer Touching
#364 posted by Mike Woodham [86.176.196.176] on 2010/06/19 19:35:54
I have created a 'trigger' entity. It covers a large portion of the map and instigates certain continuous but randomly timed actions whilst the player is inside the trigger's area. Let's call it an area_trigger.
The events are called by using the trigger's touch function, as in self.touch=do_these_things, so that when the player leaves the area, do_these_things no longer gets called. If he re-enters, the events start again. So far, so good.
I now want to 'enhance' this effect so that when the player leaves the area, a separate single event takes place, and this event takes place each and any time he leaves the area, which could be one or more times throughout the game. This event must not take place at any other time.
Is there a way to read when the player stops 'touching' the trigger so that I can call this exit event. I maybe could set up multiple triggers around the area_trigger and have them switched on by the area_trigger so that the call to the exit event is operated on a one-way basis but I am hoping there is an easier way.
Any views from the coding gurus?
 Not Easily
#365 posted by Lardarse [62.31.162.25] on 2010/06/19 20:13:30
A better solution is to have triggers at the entrances to the area. Two in fact, separated a little. The inside one calls the enter function, the outside one calls the exit function. The functions are coded so that they only actually do something on a state change.
#366 posted by necros [99.227.131.204] on 2010/06/19 23:31:26
actually, it is easy.
on your trigger_area touch function:
self.nextthink = time + 0.1;
self.think = DO_THIS_WHEN_PLAYER_LEAVES;
since touch is called every frame, nextthink will always be set higher than time, so .think will never be called. the minute the player steps out though, and .touch isn't called anymore, nextthink will expire in the next 0.1 seconds and run the .think function.
also, since i believe .touch functions are run first (before .think functions), even if you were getting less than 10 frames per second (such that the next .touch might be AFTER 0.1 seconds) the touch will be run first, thereby resetting nextthink anyway.
 Append
#367 posted by necros [99.227.131.204] on 2010/06/19 23:55:51
first: i forgot to mention in your .touch function, remember to store 'other' in self.enemy or somewhere so that your DO_THIS_WHEN_PLAYER_LEAVES function will know how to have as the activator (just add activator = self.enemy;)
if your trigger_area already needs to have a nextthink and think set for whatever reason, just spawn in a relay entity and do the trick on that entity instead:
if (self.owner == world)
{
self.owner = spawn();
self.owner.owner = self;
}
self.owner.nextthink = time + 0.1;
self.owner.think = DO_THIS_WHEN_PLAYER_LEAVES;
then:
void() DO_THIS_WHEN_PLAYER_LEAVES =
{
...........some code here............
self.owner = world; //break link with the relay entity and the trigger
self.nextthink = time + 0.1;
self.think = SUB_Remove; //delay remove
};
we set up .owner so we have an easy way to get access to the trigger_area's .enemy field, target and whatever else might be needed and we manually break the .owner connection when removing the entity because there's like a 2 second delay before entities are removed in quake.
 Crap
#368 posted by necros [99.227.131.204] on 2010/06/19 23:57:45
void() DO_THIS_WHEN_PLAYER_LEAVES =
{
...........some code here............
self.owner.owner = world; //break link with the relay entity and the trigger
self.nextthink = time + 0.1;
self.think = SUB_Remove; //delay remove
};
otherwise your only erasing self's owner (the relay entity) and not the .owner belonging to the trigger. sorry. :P
 Not Sure If That Works
#369 posted by Lardarse [62.31.162.25] on 2010/06/20 12:12:12
Because when you're in a trigger, I don't think the touch function is called every frame.
 Two Stage
#370 posted by Preach [77.98.129.22] on 2010/06/20 13:19:52
If that is a problem(it certainly would be if you need to detect monsters)can use force_retouch to help you out there. The simplest way would be to set force_retouch = 2 in the touch function as soon as you've touched the trigger. This would end up polling the heck out of all the triggers in your map while someone touched the middle one, but it would fix that problem.
I think the above is the only way to make the trigger responsive within a single frame (assuming you shrink the nextthink time lots). If you're willing to have your trigger less responsive (a minimum of two frames, but the values we pick here will be 0.2 seconds) then we can end up only using force_retouch once in 0.2 seconds.
We need the trigger_detector to have three states:
STATE_EMPTY: no player inside
STATE_READY: detected a player recently
STATE_POLLING: checking if there is still a player
If a player comes into an empty trigger we go from STATE_EMPTY to STATE_READY and wait for 0.1 seconds. After that time expires we go into STATE_POLLING for 0.1 seconds. If a player touches the trigger within that 0.1 seconds, we go back to STATE_READY, otherwise we go to STATE_EMPTY (and trigger the leaving event).
We don't actually need to explicitly track these states, they are just to understand what is going on. We have a think function called trigger_detect_startpolling along the lines of
self.nextthink = time + 0.1;
self.think = trigger_detect_fire;
force_retouch = 2;
When our .think is trigger_detect_startpolling, we are in STATE_READY. When our think is trigger_detect_fire we are in STATE_POLLING. When we don't have a nextthink in the future, we are in STATE_EMPTY.
Finally to hook all of this up, we need the touch function to set
self.nextthink = time + 0.1;
self.think = trigger_detect_startpolling;
which both moves us from STATE_EMPTY to STATE_READY when the player first touches, and back from STATE_POLLING to STATE_READY when the player retouches.
On another topic, force_retouch has an important effect on touch/think order which I hadn't considered before. When set, players will touch things they are in contact with before their think functions run (and then possibly touch things AGAIN after physics has run). So anyone who was intending to exploit the order that functions run had better be careful.
Also, I'm gonna go see if things really can run touches multiple times in a single frame. If that is the case, then it really will be important to make touch functions idempotent. This is a wonderful term from mathematics for a function which doesn't do anything else when you keep applying it to it's output. For example rint(x) is idempotent - once you get a whole number out, applying rint to that whole number just gives you the same whole number.
I'm using idempotent in a slightly weird sense here, the idea being that one of the parameters to our touch function is the value of "time", the frame that we are in. Most of the original touch functions have if(self.nextthink > time) type guards in place to achieve this, but it's something important to think about if you're writing a trigger which can be touched every frame - does it matter if you trigger it many times a frame?
#371 posted by necros [99.227.131.204] on 2010/06/21 05:03:00
i don't know why it has to be so complicated, preach... it works fine the way i said. :P no need for force_retouch or anything.
 Monsterous
#372 posted by Preach [77.98.129.22] on 2010/06/21 19:46:02
It's needed in the case of non-player entities which don't link to the world unless they move. If you were trying to detect a monster, you would need the force_retouch. It is more than what mike asked for though, the simple suffices there...
 Oh Right
#373 posted by necros [99.227.131.204] on 2010/06/21 22:56:54
i missed that you were checking for monsters as well.
 Necros & Preach
#374 posted by Mike Woodham [86.178.42.24] on 2010/06/29 20:20:15
Thanks.
 Findradius Vs Find Vs Nextent
#375 posted by necros [99.227.131.204] on 2010/06/29 20:53:37
are there any differences in how these three work?
ie: is findradius really just doing
nextent(e)
if (distance of e < dist), add to .chain
or is it faster?
for example, if i did a findradius(org, 64) where i'm checking only a small radius, is it faster than if i findradius(org, 1024) or is it the same speed?
and if smaller radii are faster than larger ones, at what point does it become better to use nextent rather than a large findradius?
i guess that kind of thing would also depend on the total # of entities as well...
 Finding
#376 posted by Preach [77.98.129.22] on 2010/06/29 21:26:43
ie: is findradius really just doing
nextent(e)
if (distance of e < dist), add to .chain
or is it faster?
It turns out that it does something extra I'd never known about - it skips any entity that's SOLID_NOT(*). Other than that, the algorithm is as you describe, but because it's written in c skipping to the next entity is a single instruction to increment a pointer, etc. So it does run a lot faster than the QC equivalent, but it doesn't do any culling of the entity list based on the bsp tree or anything fancy.
for example, if i did a findradius(org, 64) where i'm checking only a small radius, is it faster than if i findradius(org, 1024) or is it the same speed?
They are the same speed if they contain the same number of entities. Otherwise the cost of adding more things to the chain is incurred, although that's fairly light compared to the rest of the loop.
(*) Also worth noting: the distance is measured to
origin + (mins + max) * 0.5;
not just the origin as you might guess.
#377 posted by necros [99.227.131.204] on 2010/06/29 22:00:07
It turns out that it does something extra I'd never known about - it skips any entity that's SOLID_NOT
haha yeah, i figured that out the hard way. drove me insane for a while. -_-
Also worth noting: the distance is measured to
origin + (mins + max) * 0.5;
not just the origin as you might guess.
didn't know about this bit though. wouldn't have much of an impact unless you had some kind of weird offset bbox but good to know regardless. it does make getting precise findradius distances annoying though. if i did a findradius from one monster origin looking for other monsters, the find would have been completely accurate if it was going from origins and not bbox centers. oh well. :S
 How Difficult
#378 posted by megaman [91.66.119.75] on 2010/07/20 18:57:49
is it to find out what map a given savegame file is for?
Can someone post code / relevant savegame spec? :P
 Not Difficult At All
#379 posted by negke [88.70.243.227] on 2010/07/20 19:19:21
Information on the map and its entities is stored in the .sav file in plain text format.
 You're Like A Savegame Wizard.
#380 posted by necros [99.227.131.204] on 2010/07/20 21:16:01
interesting that savegames store lightstyles though. one would think that's easily gettable from the progs.
 Yeah It's Plain-text Alright,
#381 posted by megaman [91.66.119.75] on 2010/07/20 23:41:57
but the locations in the files seem to change.
I want to parse it with quakeinjector to enable loading savegames for each map, so I'd need to know how to parse the header.
Host_Loadgame_f() in http://svn.icculus.org/twilight/trunk/darkplaces/host_cmd.c?revision=10262&view=markup
seems to be the right function (darkplaces), but it's quite complicated and I'm not familiar with the quake src. For example I have no idea what COM_ParseToken_Simple(&t, false, false); does ;-) It would probably take me an hour or so to get what's going on there.
 Wait
#382 posted by megaman [91.66.119.75] on 2010/07/20 23:53:39
is it always on the same line?
#383 posted by metlslime [159.153.4.50] on 2010/07/21 04:12:01
interesting that savegames store lightstyles though. one would think that's easily gettable from the progs.
The current string for each style needs to be saved because there's no post-loadgame callback for entities to set the lightstyle strings again.
 Looks Like It's The 20th Line
#384 posted by mwh [118.92.175.237] on 2010/07/21 06:00:27
save game version, description, 16 parameters, skill and then the bsp name.
 Qc/engine Question
#385 posted by Spirit [80.171.97.116] on 2010/07/27 13:26:52
if a coder specifies a file "tORch.Mdl" would the engine usually look for tORch.Mdl or torch.mdl or what?
 Different Cases?
#386 posted by Preach [77.98.129.22] on 2010/07/27 21:04:34
From what I can glean from a quick browse through the source:
Models in pak files must match capitalisation exactly or they will not be loaded.
Models in the filesystem depend on the operating system's implementation of fopen in the standard c library. I believe this means that unix type OSs will fail to find the file but DOS and windows will succeed, but I can't find any documentation which confirms this for 'fopen'. So where possible make sure the exact case is used.
#387 posted by necros [99.227.131.204] on 2010/07/27 21:05:07
i have had problems with upper/lower case before.
i found it best to avoid uppercase altogether.
for example, ne_tower had a bunch of custom sounds.
when i was developing it, i had all the files loose in folders and setting keys like 'noise' 'necros/someSound.wav' worked fine. when i packed everything into a pak file, someSound could not be found, even though the filename hadn't changed.
 Preach
#388 posted by necros [99.227.131.204] on 2010/08/03 03:49:39
i know you've posted about this before, but i can't find it again :S
basically, there was a faster way to compare distances without using vlen.
was it something like vec1*vec2 > distance*distance ??
 Necros:
#389 posted by metlslime [159.153.4.50] on 2010/08/03 04:19:56
if (vec_x * vec_x + vec_y * vec_y + vec_z * vec_z > distance * distance) {
//temp is longer than distance
}
#390 posted by metlslime [159.153.4.50] on 2010/08/03 04:20:23
er ...
//vec is longer than distance
 Yup
#391 posted by Preach [77.98.129.22] on 2010/08/03 04:39:28
It's almost like that. You can compare the length of a vector v to a distance d with:
v * v > d * d (notice that on both sides of the equation we have the same variable twice)
If you're testing the distance between two positions p1 and p2, you need to take the difference in positions first:
v = p2 - p1;
v * v > d * d;
It works exactly as metl says, but v * v is a single QC instruction which computes the dot product he has expanded out.
 Very Cool
#392 posted by necros [99.227.131.204] on 2010/08/03 06:27:27
thank you!
when you say it's one instruction, i guess doing it as vec * vec is faster then?
#393 posted by metlslime [67.188.81.46] on 2010/08/03 08:18:25
It works exactly as metl says, but v * v is a single QC instruction which computes the dot product he has expanded out.
Ah, good to know.
 Monster_boss Glitch In Progs 1.06?
#394 posted by negke [88.70.91.228] on 2010/08/10 15:06:28
On skill 2, Chthon's aim prediction fails if the player moves towards him when he's about to throw a lavaball. The result is that he throws it backwards instead (or possibly towards worldspawn). It doesn't occur on 1.01.
Is this a known issue - why wasn't it fixed?
#395 posted by necros [99.227.131.204] on 2010/08/10 20:22:44
it's just to do with the math involved to calculate the throwing vector.
because the lavaball moves so slowly (300u/s), if you jump toward chthon, you'd be behind him by the time the projectile would hit you.
i would assume that v1.01 of the progs didn't have chthon's forward projection targetting code.
 Iterative AI And Tracking
#396 posted by Preach [77.98.129.22] on 2010/08/11 00:04:10
The algorithm is:
1) work out the time it would take to hit the current player position
2) predict where the player will be at that time
3) set the target position to be that spot
There's a logical flaw in this scheme. The time it will take the projectile to reach the new spot will be different to the time it takes to reach the current spot, so there's no guarantee that the new aiming vector will be any better. This would not be significant with a fast projectile, as the two travel times would likely be very similar, and the size of the player's hitbox is a large enough margin of error.
However, the slower the projectile moves the worse the situation gets, compounding the problem necros describes. Moving towards the origin of the shot combines these two problems, and I'll try to give an example of the worst case. The player is moving towards chthon from 600 units away (2 seconds of flight time). We imagine that the player is moving at just over 300 u/s (the player's top speed is somewhere around 400 u/s). This means that in two seconds time, the player would be just behind the knuckle that the rock is thrown from. The projectile is then thrown directly backwards and misses completely.
We realise that this target point is stupid for a few reasons:
• The player will likely not run straight at chthon for two seconds
• More importantly, the player cannot run through the solid body
• Even more importantly, the rock will sail past the target point before even a fraction of a second passes. Even if the player could and did continue exactly to the predicted spot the shot would still miss!
This last problem is something we can fix with iteration! The idea is that we want to calculate a point where the time the rock will take to reach it roughly matches the time the player would take to reach it. If the player is running towards Chthon then this point will be roughly halfway between the two. The iteration is based on
• Taking the current target point
• Calculating the time to strike that
• Calculating a new target point from the predicted position the player would be in at that time
• Feeding the new target point into the top.
In our worst case scenario we described, we'd start with a target point of the player himself. Then we'd get the point right next to the knuckle with a very short flight time, so our third point would be very near to the player, but a bit closer to Chthon than point 1. After a bit of ping-pong of points that are too near to each end, we should work into the middle.
This is quite nice, and I like iteration in AI because you can do one iteration in each animation frame leading up to the shot. It creats an interesting, slightly unpredictable thought process which keeps taking on updates as the world changes. It's worth noting that this actually offers better prediction in other cases as well.
An alternate method for a more reliable forwards-travelling shot would be this: Take the offset of the new target point from the player, a vector called o.
Apply the following equation:
o = o - (o * v_forward)* v_forward;
This removes the component of o in the direction Chthon is facing. Finally, make the target point equal to the player's origin + o. Not as elegant, but perhaps slightly easier.
 <-- Chthon Lavaball
#397 posted by necros [99.227.131.204] on 2010/08/11 00:39:58
that is... fucking cool, man.
 Heh
#398 posted by meTch [99.103.109.226] on 2010/08/11 02:05:36
I wondered why, when I go to hit the button that if I moved a step backwards and then over and than towards him as I stepped on the button I was almost always ensured not to be hit, perhaps I should have looked at him once or twice.
#399 posted by necros [99.227.131.204] on 2010/08/11 04:43:25
if the original chthon fight hadn't been so gimmicky, it would have been a cool trick akin to shambler dancing or nails + fiends.
it's sad that you barely even have to look at chthon to defeat him. :\
yes, i am bitter. it's a great model and texture. yet, so poorly used. :(
the same could be said for shub.
#400 posted by gb [89.27.241.103] on 2010/08/11 17:49:07
killable Chthons are en vogue lately.
 Probably A Silly Question...
#401 posted by necros [99.227.131.204] on 2010/08/18 22:35:28
when multiple entities a touching another entity with a .touch function, each entity runs the .touch with itself as other right?
 Touching
#402 posted by Preach [77.98.129.22] on 2010/08/19 23:09:26
Yeah, although you have to be careful with entities that aren't moving. For example, monsters at rest inside a trigger don't generate touch events, since the monster only checks for collision when moving, and the trigger never does. This is where force_retouch is required. All entities use the same code for checking collisions though, and it is a combination of descending recursively down the tree of nodes intersecting the 'self' entity, along with a for loop to test all the entities within the current node.
#403 posted by necros [99.227.131.204] on 2010/08/20 21:10:45
thanks yet again, preach :)
i was thinking maybe i should go through all your posts in this thread and make like a 'preach's guide to arcane quake facts' :P
 Well
#404 posted by Preach [77.98.129.22] on 2010/08/21 02:49:06
I do have a fun fact about that fun fact: it implies that in a multiple collision, the order that the collisions are resolved is essentially unpredictable - they depend on the location of the entities within the bsp tree that comprises the level.
Speculation: it might be possible to exploit this to glean some information about the bsp tree from QC - using force_retouch with a trigger and some point entities spawned in a region. Knowing that one point is in a leaf higher up the tree(or further left) than another may not be incredibly useful though...
 Path_corner Weirdness...
#405 posted by necros [99.227.131.204] on 2010/09/04 22:25:12
void() movetarget_f =
{
if (!self.targetname)
objerror ("monster_movetarget: no targetname");
self.solid = SOLID_TRIGGER;
self.touch = t_movetarget;
setsize (self, '-8 -8 -8', '8 8 8');
};
void() path_corner =
{
movetarget_f();
};
quoted is the path_corner entity. unlike every other entity, path_corner defer's it's setup code in another function.
as i'm passing by, i frown at it, comment out movetarget_f and just paste the code into the path_corner function and grin at my cleverness.
suddenly, none of the path_corners work anymore. so i o_O and put it back the way it was. of course, i'm left with the question of why? it's just an entity with a touch function.
 Path_corner
#406 posted by Preach [77.98.129.22] on 2010/09/05 20:11:28
I couldn't reproduce this - the monsters seemed to follow their usual paths when this was the only change made to the vanilla source code. Any chance that something else changed at the same time?
#407 posted by necros [99.227.131.204] on 2010/09/05 20:26:56
well... i dunno but it works now...
new comment:
//deprecated. why was it even like this to begin with? (not deprecated, it stopped working when i moved this down into the path_corner function o_O) un-not-deprecated: it ended up working now. o.o
 Hmm
#408 posted by nonentity [188.223.82.21] on 2010/09/19 14:42:31
Just bumping for easier location by new users (coding scares me way to much to be in here for any other reason ;)
 Self
#409 posted by necros [99.227.131.204] on 2010/09/22 22:25:51
if you change 'self' in a think function and forget to change it back, what happens? (beyond just the operations in the same think function)
does it mess up the engine's think iteration as it goes through the list of stuff?
what about entity links? can something cause a .entity link to get broken?
i'm having some weird problem with entities randomly getting messed up but it's so random that tracking it down is proving quite annoying.
 Selfless
#410 posted by Preach [77.98.129.22] on 2010/09/22 22:42:42
The 'self' that you can access from the qc side is not used (at least in the standard source) in any of the engine code, it always begins with it's own reference to an entity passed as a parameter, and then set in the global_qc_self variable (not it's actual name in the source). So I don't think that could be your problem.
Is it possible that some of the entity links you have run through entities which are removed? The quake engine has a 'lazy remove' paired with a 'thorough spawn' function. Only 5 or 6 entity fields are cleared on removed entities, just enough that they are no longer transmitted to clients. When the entity slot is reused, the spawn builtin goes through and zeroes all of the fields.
Although it makes sense to not go to the trouble of zeroing all of that memory until necessary from a performance point of view, it can make bugs intermittent. If your code relies on a reference to an entity which has been removed, then it will more than likely perform correctly until something uses that entity slot. The trouble is now that the cause of the bug is separated from it's first effect by an unpredictable length of time, making it very hard to diagnose.
#411 posted by necros [99.227.131.204] on 2010/09/23 00:37:22
i use
if (self.someEntityLink)
{
self.someEntityLink.think = SUB_Remove;
self.someEntityLink.nextthink = 0.1;
}
which i felt was pretty safe.
the problem seems to be centered around accelerating movers.
i'm still using helper entities to control velocity but it seems as if after a few minutes a helper will just become removed (when i check the helper's edict it is either free or a new entity).
however, this also happens with a custom lightning entity. the custom lightning entity spawns a chain of models to simulate the lightning effect and cleans them up when the effect is over. somehow that master entity just dies sometimes leaving the models in the game.
both of those entity's think loops seem to be solid so i can only guess something outside of their thinks are killing them.
 The Debugging Wrap
#412 posted by Preach [77.98.129.22] on 2010/09/23 11:12:04
You could put a wrapper around the remove function to try and work out exactly what is removing them. In defs.qc rename the builtin definition #15 to
void(entity e) remove_builtin = #15;
You can then define a function called remove which has extra behaviour before calling remove_builtin. I'd probably add a boolean field to the entities you want to monitor.
.float donotremove;
void(entity e) remove =
{
if(e.donotremove)
{
dprint("Entity of class '");
dprint(e.classname);
dprint(' was removed!);
}
remove_builtin(e);
}
This doesn't give you much debugging information though, it still requires you to guess what just happened. It would be better to get a stack trace, but the only way to get one of those is to crash the map. I'm not sure how much of a stacktrace you get by calling error() or objerror(e). I do know that you'll get one by creating a runaway loop though, so something like:
void(entity e) remove =
{
if(e.donotremove)
{
eprint(e);
while(0){};
}
remove_builtin(e);
}
That ought to give you plenty of information as soon as one of these entities gets removed. Just remember to clear the donotremove flag before actually removing them! Also, it should be obvious that this kind of code shouldn't go in a release build...
 Oops
#413 posted by Preach [77.98.129.22] on 2010/09/23 11:13:30
That of course should be while(1) in the code above, so that it loops forwever rather than not at all.
#414 posted by necros [99.227.131.204] on 2010/09/23 23:11:16
that's a great idea, thanks! maybe i should create a wrapper for spawn() so that donotremove is set to true by default, or do the inverse have it as 'safetoremove' defaulting to 0.
anyway, nice idea to abuse the stack trace engine feature. ^_^
it's like teaching progs new tricks but for engines. :P
 Donotremoveanything
#415 posted by Preach [77.98.129.22] on 2010/09/23 23:30:58
I was figuring you'd only apply donotremove in the spawn functions of the two entities you were trying to debug, otherwise you've got to worry about your game crashing every time a missile hits a wall and stuff! Wrapping spawn and remove is a really great trick with lots of uses, I'm really grateful to frikbot for showing me the trick of redirecting builtins.
 More Weirdness
#416 posted by necros [99.227.131.204] on 2010/09/25 00:42:31
you know how, when you're riding a platform that's moving upward, your viewpoint sort of sinks down a bit?
currently, console prints (like bprints or stuffcmd bf) are causing the view sink effect to reset each time. every time there's a bprint, the view height resets to the standard height and starts to sink again.
i have the feeling i've fucked something up pretty badly. :P
 Oh O.o
#417 posted by necros [99.227.131.204] on 2010/09/25 01:21:56
apparently, the bprint thing is happening in stock quake too. this must be some setting in fitzquake because it doesn't happen in aguirre's quake.
will investigate... o.0
 Uh Oh...
#418 posted by metlslime [159.153.4.50] on 2010/09/25 02:10:26
#419 posted by necros [99.227.131.204] on 2010/09/25 05:57:50
i'm still unsure exactly what's causing it... if someone wouldn't mind checking this out, an easy way to test this is to bind a key to 'god' and then load up e1m1. hit the button for the first lift and let it lower.
when it starts to raise back up, repeatedly hit the key you bound to god mode. each time the screen should reset to the normal view height before sinking back down.
this happens in fitzquake and quakespasm.
 Incidentally
#420 posted by necros [99.227.131.204] on 2010/09/25 06:00:52
i only noticed this happening because i have some debug code that outputs a ton of text repeatedly to the screen. with that many outputs, the screen practically shakes when riding a lift up.
it's not like it's really a big deal since when you play normally outside of developer 1 mode, you don't get the outputs and so don't get the shaking.
on a possibly(?) related note, monsters riding a lift up appear to not interpolate their positions if they are walking on the platform?
#421 posted by metlslime [67.188.81.46] on 2010/09/25 19:19:38
on a possibly(?) related note, monsters riding a lift up appear to not interpolate their positions if they are walking on the platform?
yeah, I noticed this recently. Must fix!
As for the view jerkiness on lifts... I've seen this but it didn't notice a connection to console prints. Will investigate.
#422 posted by necros [99.227.131.204] on 2010/09/25 21:41:16
possibly helpful:
it is not strictly bprints that cause this. when i turn the console spam off, every so often the view will jerk rarely.
 Engine/editor/compiler Coders Please Help!
#423 posted by than [180.146.63.212] on 2010/10/03 19:17:48
I got this urge to try and write my own Quake map editor for fun (don't hold your breath) and I am already stuck at the first hurdle (for this reason).
I don't know why, but I thought I would try and load a wad file first. Just so I understand the format I thought I'd read about it and implement it myself. I've also got the code from the engine to look at, so it's not super difficult, but I am having a weird problem.
When trying to read the individual lumps that contain the image data for textures, if I try and read the width or height value I just get nonsense UNLESS I add a weird 16 byte offset to the pointer I am using.
example:
LUMP_t* lump = (LUMP_t*)(waddata + lumpinfos[lumpno].filepos + 16);
cout << "width: " << lump->width << ", height: " << lump->height << "\n";
will output the correct width and height, but if I remove the 16 byte offset, it doesn't work and I get gibberish.
My problem is that I have no idea why I need to add the 16 byte offset, and am worried that it might cause problems down the road if I don't understand why it's there.
Aside from that offset, everything seems to be as I expected.
 Than
#424 posted by SleepwalkR [130.149.148.83] on 2010/10/04 12:03:09
My tip: try and implement some simple editing functionality as quickly as possible because that will keep you motivated. Don't write struts code like reading wad files. Write your internal model for brushes and write a simple renderer for that. Then, improve on that code. If you have to write code that doesn't draw anything on screen for weeks, you will very likely lose your motivation quickly.
 Sleep
#425 posted by than [182.164.25.24] on 2010/10/04 13:00:37
thanks for the tip. I know it can be really boring to write code that doesn't draw stuff, but for some reason I like writing file loaders and figuring out how stuff works. My plan for tonight is to get wad textures displaying on screen and then I want to go onto the exciting brush stuff and improve my 3d math knowledge (I forgot most of it... oops).
I don't think I will be able to write an editor as awesome as Willem's Toetag, but if I get even 1/4 of the way there, I will have learnt a lot :)
 One Tip
#426 posted by SleepwalkR [130.149.148.83] on 2010/10/04 14:10:44
Brushes are represented in map files as the intersection of a number of half space equations (each face is such an equation). You must convert this representation into a representation that you can use to draw stuff, i.e. polygons which you send more or less directly to OpenGL. There are several techniques to do this by calculating the extreme points of the solution of the original system of (inequality) equations. These techniques are computationally optimal, but very hard to implement correctly. I suggest you don't touch that stuff for your first version.
Another very simple way of converting a brush to polygons that you can draw is to start with a cuboid polyhedron (represented by its vertices and edges) with maximum dimensions and then simply split the brush along the planes which are defined by the faces. This is easy to do because you just have to intersect all edges of the polyhedron with the splitting plane. You'll end up with a polyhedron that has the same shape as the brush, but you can easily determine the face polygons from that data structure. This is computationally inefficient, but since you are not dealing with a lot of data, it's fast enough.
Another tip is to use the vertex / edge representation only for rendering, not for manipulation of the underlying brushes. The brushes should remain in their original representation and should be manipulated in that representation as well, This way you can use the very high precision that the half equation intersection representation offers (and don't have to convert float vertices back to int).
 Sleep: No No
#427 posted by bear [217.115.56.186] on 2010/10/04 17:50:49
implement rounding errors or some other form of sloppy calculations so it will feel just like using qoole!
 Thanks For The Tips
#428 posted by than [182.164.25.24] on 2010/10/04 18:33:43
I got my wad loader working ok and it renders textures from a 570 texture wad just fine. The code is a total mess and I still don't know what that weird 16 byte offset is, but I got Quake textures displaying on screen in sexy Quake colours, so I'm happy for today. Next step will be a map loader :)
I made a map compiler (not to bsp, but to a much simpler format that just uses polygons) before, so I still have some code that can create polys from brushes somewhere. I was going to use that. Pretty sure it uses the clipping method. The first solution sounds difficult :)
this?: http://en.wikipedia.org/wiki/Convex_polytope#Vertex_representation_.28Convex_hull.29
Math on wikipedia is always extremely hardcore sounding.
 Just Had A Look
#429 posted by than [182.164.25.24] on 2010/10/04 18:48:45
at my old brush compiler code and it appears to take a series of 3 planes to generate a vertex and then adds the generated vertex to a vertex list for the each face involved in its calculation. It iterates through this until it's done and looks very inefficient.
But if it works, I don't care :)
When editing a map, most of the brushes just sit there unselected. I would imagine the average user doesn't touch more than a handful at once, and even then most of the operations are probably moves.
 Probability Of Attack
#430 posted by necros [99.227.131.204] on 2010/10/05 20:07:17
anyone who's studied this could answer a question?
if i've got a monster who has an 80% chance to attack when his checkAttack function is called:
if (random() < 0.8)
attack!
does that really mean he has an 80% chance to attack at all times? or is it more like 10.7% chance to attack every second? (0.8 ^ 10 since animation rate is 10fps)
probability has always been pretty impenetrable for me. :S
as a result, i tend to rely much more on 'cooldown' (attack_finished) timers to regulate monster attack rates.
 Geometric Distribution
#431 posted by Preach [77.98.129.22] on 2010/10/05 21:53:02
The code you posted means he has an 80% chance to attack each frame. One of the best ways to understand what this means is to look at the probability that the monster will start attacking before the 2nd, 3rd, 4th frames etc.
The easiest way to do the calculation is to flip the question on it's head. What is the probability that we are still not attacking on the 2nd, 3rd, 4th frame? For that to be the case, we must have failed to attack in all the previous frames, and the chance of that is 0.2 each time. Since each trial is independent, we can multiply them together, as follows:
Frame 2: 0.2 * 0.2 = 0.04. 4% chance of not attacking after the second frame
Frame 3: 0.2 * 0.04 = 0.008. A 0.8% chance of not attacking on the third frame or earlier.
Frame 4: 0.2 * 0.008 = 0.0016. Scarcely a 0.1% chance that we are not attacking 4 frames of considering it.
So it's pretty certain we'll attack within the first 3 frames, our code is largely creating variety in behaviour over a range of just 0.3 seconds. Even if we changed the probability to 0.5 we'd still expect the monster to attack quite quickly: 1 / (2^10) is the probability that we wouldn't have attacked after 1 second - which works out at > 0.1%.
Using attack_finished as a cooldown is probably the best way to to long pauses out of your monsters, if you want them to choose between attacking with a missile or closing the distance with the player.
 Yeah
#432 posted by necros [99.227.131.204] on 2010/10/05 23:25:20
that makes a whole lot more sense. i confused myself over why the chance to attack would go down over time, which is just stupid because every time we check, we are giving a new chance to attack.
 Quick Question
#433 posted by than [180.147.88.240] on 2010/10/07 16:21:16
I have a feeling I could find this if I dug through the Quake source, but are the lengths of key/value pairs for map entities limited to 16 and 32 chars respectively? If not is there some other limit? Does anyone know.
On top of that, if anyone happens to know the max number of:
entities in a map
faces per brush (guess this is compiler limited)
key/value pairs per entity
I'd love to know them :)
 ^^
#434 posted by necros [99.227.131.204] on 2010/10/07 19:04:03
 Thanks
#435 posted by than [180.147.84.55] on 2010/10/08 00:20:21
1024 seems quite a lot. I'll just get rid of the limits I put on my map loader.
Texture names do appear to be limited to 16 chars though.
#436 posted by metlslime [159.153.4.50] on 2010/10/08 00:39:27
Texture names do appear to be limited to 16 chars though.
15 chars unfortunately, since you need a null terminator.
#437 posted by Spirit [80.171.82.183] on 2010/10/08 16:25:55
This is not QuakeC related. The answer is hopefully simple algebra but I am too stupid to figure it out for myself and Google is not helping.
Let's say I have these 2D coordinates:
1) 10;10
2) 54321;12345
and want to fit them into a smaller (let's say 800x800) window. How would I code that? Do I really need to make an affine transformation? If yes, no need to explain the how, I should know that.
 ";" Is Not A Name
#438 posted by jt_ [24.11.39.160] on 2010/10/08 22:57:46
frikqcc keeps complaining about ";" not being a name in the following function, but I can't any ;'s being used as names, or any stray ones that might being messing with things. This is just the BackpackTouch func from progs106
<code>
/* PLAYER BACKPACKS */
void() BackpackTouch =
{
local string s;
local float best, old, new;
local entity stemp;
local float acount;
if(other.classname != "player")
return;
if(other.health <= 0)
return;
acount = 0;
sprint(other, "You get ");
if(self.items)
if((other.items & self.items) == 0) {
acount = 1;
sprint(other, "the ");
sprint(other, self.netname);
}
// if the player was using his best weapon, change up to the new one if better
stemp = self;
self = other;
best = W_BestWeapon();
self = stemp;
// change weapons
other.ammo_shells = other.ammo_shells + self.ammo_shells;
other.ammo_nails = other.ammo_nails + self.ammo_nails;
other.ammo_rockets = other.ammo_rockets + self.ammo_rockets;
other.ammo_cells = other.ammo_cells + self.ammo_cells;
new = self.items;
if(!new)
new = other.weapon;
old = other.items;
other.items = other.items | new;
bound_other_ammo();
if(self.ammo_shells) {
if(acount)
sprint(other, ", ");
acount = 1;
s = ftos(self.ammo_shells);
sprint(other, s);
sprint(other, " shells");
}
if(self.ammo_nails) {
if(acount)
sprint(other, ", ");
acount = 1;
s = ftos(self.ammo_nails);
sprint(other, s);
sprint(other, " nails");
}
if(self.ammo_rockets) {
if(acount)
sprint(other, ", ");
acount = 1;
s = ftos(self.ammo_rockets);
sprint(other, s);
sprint(other, " rockets");
}
if(self.ammo_cells) {
if(acount)
sprint(other, ", ");
acount = 1;
s = ftos(self.ammo_cells);
sprint(other, s);
sprint(other, " cells");
sprint(other, "\n");
// backpack touch sound
sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
stuffcmd(other, "bf\n");
// remove the backpack, change self to the player
remove(self);
self = other;
// change to the weapon
if(!deathmatch)
self.weapon = new;
else
Deathmatch_Weapon(old, new);
W_SetCurrentAmmo();
};</code>
 Deception
#439 posted by Preach [77.98.129.22] on 2010/10/09 00:14:24
The error message is true but unhelpful. It's trying to use a ; as a name, but what that means is that it's reading a line in a way you didn't intend. Often you get unexpected parsing errors when you leave a function earlier or later than expected. In this case you're missing the closing braces for the self.ammo_cells block, and so it's reading some further code incorrectly.
I know that func_ eats indentation(unless you're really patient with inserting nbsp character entities) so I can't say if missing indentation might have made this harder to spot. But I can recommend editing code in something that can highlight matching braces in some way - I pasted the code into notepad++ to check the matching. I will concede that knowing it could be a mismatched brace based on the error was really key, so it's not all software solutions.
 Hat Tip
#440 posted by jt_ [24.11.39.160] on 2010/10/09 00:32:49
That was it, thanks Preach. In my editor (acme) everything is indented fine, but as you said func_ at them. Wish func_ has support for <code></code> tags.
 Don't Forget To Spellcheck...
#441 posted by jt_ [24.11.39.160] on 2010/10/09 00:33:58
s/at/&e
#442 posted by necros [99.227.131.204] on 2010/10/09 02:23:15
a preformatted tag would be nice, but that would likely break the forum width?
mind you, the forum could probably get twice as wide without bothering anyone.
#443 posted by Spirit [80.171.27.31] on 2010/10/09 08:23:06
No, absolutely not. Apart from the colours and no-clutter, the 72-80 character line length ensures the great readability of func. Forums that spread to full-width (or anything remotely like that) are an abomination.
Use http://www.inside3d.com/pastebin.php , that even gives you syntax highlighting. Also be aware that func has a preview button. ;)
 Yeah
#444 posted by RickyT33 [82.26.222.218] on 2010/10/09 14:59:28
No offence to Quakeone.com for example, but having like more than 12 words on a line is a bit of a no-no. Just hurts my eyes :)
 Good Point
#445 posted by ijed [190.22.73.244] on 2010/10/09 17:45:18
 Ok...
#446 posted by necros [99.227.131.204] on 2010/10/09 19:37:21
 Ropes...
#447 posted by necros [99.227.131.204] on 2010/12/07 02:45:52
so i was wondering... how hard would it be to create some kind of dynamic rope thing in QC?
i'm thinking, you would put down a func_rope and then specify the length of the rope. then target at an info_notnull.
for the code, i first thought it would be pretty easy, all you'd have to do is first spawn an entity chain and then set each of the nodes in the chain to obey quake gravity.
then, all you'd need to do is check every frame to make sure the next link hasn't moved out of range and if it has, move it back along a straight vector.
but then i started thinking that you can't just iterate forward through the chain because you would have two anchored positions with only the center moving freely and then my head exploded. :(
 Oh
#448 posted by necros [99.227.131.204] on 2010/12/07 02:48:37
and this is the best part: i started trying to code it because i was too lazy to make brushwork wires in my map. ¬_¬
#449 posted by metlslime [159.153.4.50] on 2010/12/07 03:50:25
ropes are easy enough, just set up a havok-like physics system and include inverse kinematics, then set up the constraints between your rope links, and mark the two ends as unmoveable. :)
 You Have To Burn The Rope From Both Ends At Once
#450 posted by Lardarse [62.31.162.25] on 2010/12/07 03:52:34
With two anchor points, you have the trail of gravity come from both at once. The only tricky situation is in the middle.
 Actually....
#451 posted by metlslime [159.153.4.50] on 2010/12/07 03:55:34
if all you want is a rope that doesn't collide with anything, including itself... it's doable.
To solve the rope position for a static rope, you just set it up at spawn: guess and then iteratively refine the locations of all entities until it's within a certain tolerance.
If you want it to be dynamic, you don't need iteration, but you give the rope some elasticity and then have it accelerate to the correct position every frame. With the right values, it will look pretty good. Otherwise it will be bouncy and rubbery and go crazy.
 Of Course...
#452 posted by metlslime [159.153.4.50] on 2010/12/07 03:58:08
You also need to render the rope. I guess you would use a model that represented a segment of rope X units long. Whenever the distance between segments is not X, you will see gaps or overlap. Or have a bunch of frames in the .mdl to represent a range of distances, and quakec can select the frame based on the actual distance between joints on that frame.
 Sounds Cool
#453 posted by ericw [206.75.128.68] on 2010/12/07 04:00:43
Here's one tutorial I found, not sure how easy it would be to implement in quakec though: http://freespace.virgin.net/hugo.elias/models/m_string.htm
#454 posted by mwh [202.124.96.158] on 2010/12/07 05:12:42
If it's static, a rope hangs in a cosh curve ( http://en.wikipedia.org/wiki/Catenary ). You can just calculate it with a scientific calculator I guess :-)
 Ropey Mechanism
#455 posted by Preach [77.98.129.22] on 2010/12/07 21:10:04
The thing I'd want the most from creating a good rope system is just frustratingly out of reach of the QC - to be able to control endpoints of a polygon independently of each other. The use would be to attach some end of a polygon to one "entity" and the other end to another, so you could create a continuous mesh that you could deform individual segments of.
Without that, I'd say you're better off just creating a static mdl prop to represent a rope. One trick that I think could work well in a map is creating a reaction to "wind", and ropes would be a great prop for displaying it. The idea is to have a global wind variable which stores a value between say 0 and 40 representing the wind force in that frame.
You'd want a slow random walk which would move the wind through these values, it's possible that adding crandom()(sic) to it every 0.1 seconds and capping the value within the range would suffice. Scaling the adjustments by frametime(and then back up with a larger constant) would allow you to recalculate the wind strength every frame which might improve the animation. It might also benefit the model to make it more likely to move the wind towards the middle values than the extremes.
You then need props through your level like ropes, "ye olde inne" signs, torches, lanterns and flags which are specially designed to react to the wind. They might be give specially designed models which have frames from 0 to 40 corresponding to the strength of the wind. Then they would only need to have think functions which regularly update the entity's frame to match the wind in that frame, maybe with some jitter.
In some cases, like the sign at the inn, you might only be going for simple rotation back and forth. Then you would be better served using .angles rotation since some engines transmit it with higher precision, and you would avoid the floating vertices rotating a sign two degrees each frame is bound to produce. You would also not need to use granular values between 0 and 40, but just use the floating point wind value directly to calculate the angle.
Then just add some howling wind and creaking timber sounds and your windswept landscape is complete!
#456 posted by necros [99.227.131.204] on 2010/12/08 01:41:38
i was actually not going to bother continuing but those posts kind of encouraged me to at least try...
ended up with this:
http://necros.quaddicted.com/temp/ropes1.jpg
each segment is 16-32 units long (they contain 16 frames in 1 unit long increments).
each frame, i iterate through the chain and add a velocity vector pointing towards both the next and previous points.
this works somewhat, but you have to tweak the tension (speed multiplier of the velocity vector) or it jitters a lot.
it also doesn't really work with longer ropes because you need super high tension to keep it from falling apart but those levels of velocity cause excessive jittering.
so yeah, with the expense of iterating the chain every frame and needed many segments with 1 entity each, it just doesn't seem worth it.
if i do try to continue with ropes generated at run time, looks like i'll have to look into static ropes, probably with a cosh function like mwh posted (thanks for that).
it's a shame though because i had hoped to get the ropes to react to rockets passing by and explosions. oh well. :S
 Just Noticed Another Problem
#457 posted by necros [99.227.131.204] on 2010/12/08 02:06:59
if your FPS drops, the required velocity to keep the segments together becomes increasingly larger. at some point around 30-45 fps, the velocity is too high and the chain breaks.
 HeLp ?
#458 posted by delore [151.66.161.90] on 2010/12/12 17:35:41
..my idea is to have in my map many different skinned monsters per class (4 or 5 soldiers with different colors, 4 or 5 knights, ..)
Easiest way to achieve this ?
-I'd happily skip the creation of every different skinned monster in qc code(since I want to change only clothes color for each!)
#459 posted by negke [88.70.92.65] on 2010/12/12 19:18:17
Store the new skins in the mdls; give the monsters a "skin" "#" field in the map (# being the index number of the respective skin).
 Ffs Don't Crosspost
#460 posted by negke [88.70.92.65] on 2010/12/12 19:19:36
#461 posted by necros [99.227.131.204] on 2010/12/12 19:20:31
there's 2 ways to create reskin monsters.
1. Create all new .qc files for each reskin, using the same frame macros but renaming the function names (so they don't conflict at compile time).
2. Integrate all the types of monsters into the same original monster code so that at key points in the code, it checks to see what type of reskin it is and then behave different accordingly.
method 1 is the easiest to understand and and read because everything is seperated into individual files. the monsters will adhere to the standard monster coding setups.
method 2 is the easiest to code because you don't have to rewrite anything and just add in little snippets for things like different attacks or a different ai_run routine.
also of note, a lot of the behaviour is controlled by the checkattack function, so simply having a seperate one of those can help distinguish between reskins.
if you're planning on doing this much coding, you should probably check out inside3d. they are more focused on coding while this board is more focused on mapping.
#462 posted by necros [99.227.131.204] on 2010/12/12 19:21:10
re 460: clairvoyant? o.0
 Oh Nm
#463 posted by necros [99.227.131.204] on 2010/12/12 19:27:15
i see what you meant now.
also: http://www.youtube.com/watch?v=21D-21MLrAE
not sure what those 'shivers' are... i can't only guess it is a symptom of irregular framerate. a momentary dip would cause it, i suppose, although i thought i fixed that. :P
also, i obviously need to find some way of adding in damping of some sort because those things will bounce around for ever.
 Lost Chapters Src
#464 posted by jt_ [24.11.39.160] on 2010/12/18 07:44:05
Does anyone have/have a link to the lost chapters src from qexpo? http://qexpo.quakedev.com/booths.php?tag=necros doesn't go to the page. I've seen it linked somewhere here, just can't find it..
#465 posted by gb [89.27.197.65] on 2010/12/18 09:54:45
 Ty
#466 posted by jt_ [24.11.39.160] on 2010/12/18 14:15:49
#467 posted by necros [99.227.131.204] on 2010/12/19 01:45:59
http://necros.quaddicted.com/temp/qcgui1.jpg
another program with debatable usefulness. :P
#468 posted by necros [99.227.131.204] on 2011/01/15 04:46:36
is it possible to determine if the player is inside a triangular space with just the info of the 3 vertices and discounting vertical axis with QC?
making a monster that traps the player inside a triangular area but it would be awesome if the monster could tell if you were actually trapped (inside) or not.
#469 posted by necros [99.227.131.204] on 2011/01/15 04:49:54
god damn it...
as usual, after thinking about it for a few minutes, i figure it out a few seconds after posting.
i can just use the dot product of normalized vectors from the origin vertex.
we need a delete button. :P
 Rapid Fire Round
#470 posted by Preach [62.30.197.42] on 2011/01/16 13:25:57
Ok, I've got an idea to share with y'all about making QC events that happen at high frequencies cope with the framerate dropping below that frequency. But in order to make it a bit different, I'm going to set a bit of a puzzle about it first, which comes as a piece of code and three questions:
void() generic_think =
{
// do some kind of thing which needs to
// occur rapidly
self.nextthink = self.nextthink + 0.05;
self.think = generic_think;
if(self.nextthink <= time)
self.think();
}
• For partial credit, what is this code trying to do?
• For full credit, why will it fail?
• For extra credit, what can we do to fix it?
#471 posted by necros [99.227.131.204] on 2011/01/16 19:56:35
it looks like you're trying to get the think function to recursively take care of missed thinks.
i've never thought of doing it this way. usually, if i have a think function that needs to be accurate across inaccurate think times, i just use something like this:
void() thinkfunction =
{
fraction = (time - self.ltime) / 0.05;
self.ltime = time;
self.nextthink = time + 0.05;
self.think = thinkfunction;
}
and just scale whatever it is i'm doing with fraction.
doing it recursively would be easier to code, i guess, but i would think much more expensive on operations.
 Tail Recursion After This Message...
#472 posted by Preach [62.30.197.42] on 2011/01/16 22:59:49
That's exactly the point of the code, so here's what goes wrong with it:
The assumptions behind this bit of the code are that the QC global time stores the current server time, and self.nextthink stores the time we wanted the think to occur. One of these things is often not the case, and the other is always incorrect.
If you run a dprint on self.nextthink during a think function (but not an animated think function) you will find that nextthink is equal to 0! It's always reset by the engine, so that unless you explicitly call for a new nextthink, the engine can skip over thinking. Conversely, nothing happens to the think field when you run a think function, so if you're optimising QC code for a looping think function, you can remove the bit where you reset self.think in each call safely.
So that's the assumption that's always wrong, that the nextthink time you originally set is preserved in that variable when the think function eventually runs. But is the information lost forever? Not always! The QC variable time is set to either the current server time, or the actual nextthink time which WAS set - whichever is the largest. So as long as you don't ever set nextthink to be smaller than the server time + frametime (which calculates the server time for the NEXT frame), you get the information back.
Luckily never doing that is the point of this whole missed-think-avoidance code. All we need now is to find out the true server time during our think. This is easy though, as we just create a new global called servertime. We then use StartFrame to set servertime = time, and then refer to that in our calculation.
Our code then looks like:
void() generic_think =
{
//do stuff
self.nextthink = time + 0.05;
if (self.nextthink < servertime + frametime)
self.think();
}
As a closing remark, this function has tail recursion, so you don't actually have to fill up the callstack repeating it over and again. Just wrap it in a do...while loop for performance.
And there we go, a way to ensure that a given function executes 100 times in a second, regardless of the framerate of the server.
#473 posted by necros [99.227.131.204] on 2011/01/17 01:37:55
clever! :) i had no idea about time being set to nextthink.
also, you could just make a new .nextthink2 var:
self.nextthink = self.nextthink2 + 0.05;
this neatly avoids the engine resetting nextthink.
 Help With Those Damn .lmp Files !
#474 posted by delor3 [151.66.165.238] on 2011/01/30 14:01:23
Hi,
how can I modify those .lmp files included in id/paks ?
my goal is to have a new hud for my mod (at least change color and quake guy face !)
#475 posted by necros [99.227.131.204] on 2011/01/30 19:32:40
adquedit can import bmp and pcx (i think?) and convert them to lmp.
 Lmp2pcx
#476 posted by jt_ [24.11.39.160] on 2011/01/30 19:57:22
Or is it pcx2lump..i have one of them on my laptop, i can see if i can dig it up.
 QuakeC Source Code Licensing Status
#477 posted by metlslime [159.153.4.50] on 2011/03/01 20:12:04
So what's the licensing status of the quakec source code? I was planning on releasing the rubicon 2 source, but not sure what license i can put on it (e.g. GPL)
I know that the original source release was sort of an informal "you can make quake mods with it" type license, but not sure if there was a more recent GPL release of the same code. And whether it applies to hipnotic code as well (since i'm using the hipnotic rotating code.)
 Useless Qc Observation Of The Day
#478 posted by Preach [62.30.197.42] on 2011/03/18 11:03:45
It turns out that the builtins floor, ceil and rint are not as efficient as abusing the bitwise functions.
So if you're optimising a tight loop with a call to floor(x) you can instead substitute:(x | x) which does the same thing. Similarly ceil(x) can be replaced by ((x | x) + 1). rint(x) is a little more complicated to replace, it takes two statements:
x = x + 0.5;
(x | x);//is now the same as rint(x) before the first line
Note that you can't make a helper function like
float(float x) rint2 =
{
x = x + 0.5;
return x | x;
}
- because the efficiency saving arises from avoiding the function call overhead, and you waste that by making it a function instead. Also, reducing the number of instructions is only really worthwhile in a tight loop that might trip the runaway-loop counter. Hence this being the useless qc observation of the day...
 Except That
#479 posted by Lardarse [62.31.162.25] on 2011/03/19 04:40:22
((x | x) + 1) is incorrect for ceil() as if x==floor(x) then you get a number that's 1 higher.
 True Dat.
#480 posted by SleepwalkR [85.178.118.246] on 2011/03/19 07:25:11
 Man
#481 posted by necros [99.227.131.204] on 2011/03/19 07:31:39
i didn't understand any of that. :(
what is |? i only know it's the bitwise add operator. never heard of using it with normal numbers.
 | Is Bitwise OR
#482 posted by Lardarse [62.31.162.25] on 2011/03/19 08:01:46
However, since it can only work with integers, it floors each number before doing the OR.
 Doh
#483 posted by Preach [62.30.197.42] on 2011/03/19 10:15:06
Yeah, I completely fluffed that one. I guess you'd need to do something along the lines of
temp = (x|x)
(temp != x) + temp;//this ACTUALLY evaluates to ceil x
Some lovely abuse of the boolean to float conversion there. I'm not sure if that's still fewer instructions than the call to ceil though...
 More Negatives
#484 posted by Preach [62.30.197.42] on 2011/03/19 13:29:07
The "better" version of ceil still doesn't work for negative numbers, and you might not get the same results as you expect for negative numbers using the rint substitute either. So they're both limited in scope. The floor one works well though, since it does the least work...
 Is Qc Really That Slow
#485 posted by jt_ [24.11.39.160] on 2011/03/19 14:45:16
That crap like that matters? :s
 In This Case
#486 posted by necros [99.227.131.204] on 2011/03/19 19:02:41
it's not about speed at all. preach already explained that it's main usefulness comes from reducing the number of operations done, thereby increasing the amount of things you can do in a while loop before the engine complains about it.
 Well Maybe
#487 posted by jt_ [24.11.39.160] on 2011/03/19 22:10:51
Someone should make the engine not complain about how many instructions are being done. That seems.like a better fix than pretty much inlining every function call.
 Rationale
#488 posted by Preach [62.30.197.42] on 2011/03/19 23:24:16
That would mean that if you ever code an infinite loop in qc then the engine would hang rather than just drop the server with a runaway loop error message.
 Good Point
#489 posted by jt_ [24.11.39.160] on 2011/03/19 23:36:41
Maybe then how many instructions are needed for a runaway error to be trigger should be increased? It would seem so if the kind of optimizations that were listed earlier are needed to stop runaway. Or maybe I'm crazy.
 Been A While Since I Did QC
#490 posted by Kinn [86.153.224.11] on 2011/03/20 01:09:58
but how many loops would trip the runaway loop counter?
 100000
#491 posted by Preach [62.30.197.42] on 2011/03/20 01:20:21
100000 instructions between QC programs - a program being a succession of QC functions called without control returning to the engine. In general this is a sensible limit. An example where it might be a problem is if you need to run a looping on each of a set of entities, 20 entities would leave you only 5000 instructions for each one, disregarding overhead. Whatever you set the loop limit to, you could always push the boundaries, until the computation speed becomes more of a factor.
Of course by then you have a new excuse to optimise. The profile command suggests that once upon a time qc performance was an issue, and if quake were to be popularised in mobile or flash form, it might yet matter.
 Simple Idea
#492 posted by ijed [190.22.6.191] on 2011/03/20 02:24:06
Lower it for developer 1? Or have a runtime 'reader' to let you know exactly what's going on?
Like an ingame debugger.
 Maybe Not Lower It, But
#493 posted by Lardarse [62.31.162.25] on 2011/03/20 02:40:35
Have it print to console every 10k, noting the current stack and position. Or maybe even 5k...
 Yeah,
#494 posted by ijed [190.22.6.191] on 2011/03/20 03:33:57
Advanced logging.
 Qc Dev Tools
#495 posted by Preach [62.30.197.42] on 2011/03/20 12:07:57
Having extra qc developing tools in engines would be a blessing, but they wouldn't help with this problem because they won't ever be universally adopted - making a mod than only works in engines that have a raised instruction limit would not be wise. By that point you might as well customise the engine to do the intensive calculation for you and add it as a qc extension. It's not the kind of thing that can be set to "progressive enhancement" either - you can't change the logic of your code to suit the capacity of the engine that is running it.
At some point I want to write down my thoughts of "progressive enhancement" - usually a web design term - and how it relates to Quake. It can explain why features like fog and skyboxes were embraced, but things like qc extensions on the whole were not.
 That'd Be Interesting
#496 posted by ijed [190.22.48.69] on 2011/03/20 12:39:15
The question is, how can QSB be made.
 Honestly
#497 posted by necros [99.227.131.204] on 2011/03/20 23:24:53
i've never really had any problems with the 100k instruction limit and i've done all kinds of weirdo shit in while loops.
the point where you start to hit the limit, you're better off thinking about deferring operations to the next frame or something.
 Yeah
#498 posted by Preach [62.30.197.42] on 2011/03/20 23:37:15
While I've never had anything proper reach the loop limit yet, I know that it was a problem in Prydon Gate, so I guess it depends how different your mod is. The further you go from the original game, the harder you have to work in qc I guess...
 Interesting
#499 posted by Kinn [86.153.224.11] on 2011/03/22 21:05:52
If I started hitting the 100k limit in QuakeC I'd probably be at the point where I need to be doing an engine mod, not a QC mod.
#500 posted by necros [99.227.131.204] on 2011/03/23 04:06:27
speaking of instructions...
i've been trying to figure out a way to be able to have two huge groups of monsters fight each other without slowing down.
i'm talking like 2 or 3k monster teams here.
been experimenting with sort of deferring all ai functions to a 'group leader' but it's sort of hit and miss. you either have like a static group and when you have intermittent LOS, then some of the group can't hit their target, or you have a dynamic group and the code to figure out what group you're in eats up even more time than just running ai on all monsters like normal. :\
 Multithread It!
#501 posted by jt_ [24.11.39.160] on 2011/03/23 07:32:53
Oh wait...
 Show Of Hands
#502 posted by Preach [62.30.197.42] on 2011/03/30 01:31:00
Quick straw poll here:
If I was going to invest some time in a qc project, which would be most useful to mappers?
1) A medium-range navigation system for the AI. Where monsters now walk straight at the player over gaps they can't cross, this system would direct them around to the bridge. Basically navigation on the scale of rooms, not levels.
2) A system to create alternative shapes for triggers. For example, cylindrical, spherical, rotated rectangles, composition of multiple triggers into a single unit.
3) create an event-based system for with inputs and outputs on doors and other funcs. For instance, allowing you fire triggers on the events of a door beginning to open, reaching closed position, being blocked, etc.
On the input side rather than having just a trigger, you might be able to command a door to open (does nothing if it's already open), or shut (vice versa ), or toggle (the old behaviour). Having a system of 'filters' would allow conditional triggers like "pass this input on if door X is still moving".
 In Order (favorite Idea First):
#503 posted by RickyT33 [86.31.169.218] on 2011/03/30 01:54:58
AI first
I/O Triggers second
trigger b-box control third.
I guess all would have their uses, but better nav AI for monsters is the coolest idea IMO :)
 Ai
#504 posted by jt_ [24.11.39.160] on 2011/03/30 02:57:25
Would be neat to give monsters specific commands, ie attack this, run over there etc. :E
Being able to give things specific triggers would be great, for example, forcing a door to close only on a specific trigger, or making func_trains that can be made to reverse and go backwards through their track. :)
 3
#506 posted by Drew [132.205.103.141] on 2011/03/30 03:29:29
I would vote 3, but I don't really *release* maps, so...
 AI
#507 posted by Lardarse [62.31.162.25] on 2011/03/30 04:39:39
 3!
#508 posted by Spirit [82.113.106.203] on 2011/03/30 08:51:06
Quake is a simple pattern based arcade shooter that lives from its simplistic ai. 3 would allow people to create more atmosphere rich maps.
 1!
#509 posted by negke [88.70.236.23] on 2011/03/30 10:54:31
Actually, all three.
 1
#510 posted by onetruepurple [213.227.88.32] on 2011/03/30 11:36:14
 AI
#511 posted by ijed [190.22.113.202] on 2011/03/30 12:52:42
 1...3...2
#512 posted by generic [67.233.207.122] on 2011/03/30 13:43:54
I can't count :)
 Thoughts
#513 posted by Kinn [109.158.79.63] on 2011/03/30 21:15:35
1) sounds like it would have the most tangible impact on the gameplay, although purists might argue that it would feel wrong to have Quake monsters capable of relentlessly chasing the player from room to room.
That said, I did feel the need to mackle up a very basic system in my maps to allow the monsters to chase the player up and down some of the spiral staircases, that otherwise they would have had real problems with.
2) sounds like its use would be too limited. 90% of the time, axis-aligned boxes will do the job, although I might as well admit that in Marcher I hacked in a sort of line-segment trigger (that functioned like an arbitrarily oriented invisible tripwire) which I used in a couple of places.
3) Sounds very useful all round and is a philosophy I wish Quake's trigger system had adopted from the beginning.
 Clarification
#514 posted by Preach [62.30.197.42] on 2011/03/30 23:38:39
Without wanting to influence anyone's votes
to allow the monsters to chase the player up and down some of the spiral staircases
This is almost exactly the use case I had in mind - a system that would be capable of allowing this, or for creatures to know how to move from a balcony, down the stairs into the atrium where the player was. The trick is making a single system flexible enough to do that without being a nightmare to set up.
It wouldn't let monsters chase you from room to room, you'd have one trigger brush creating a region, and if the monster and the player were both touching the trigger then the monster would be told the direction which moves them topologically closer* to the player. Hopefully that doesn't compromise the fundamental behaviour of any monster, just allows them to deal with complex rooms as well as open spaces.
* As opposed to the direction bringing them physically closer - the current navigation method. In open spaces, the two are the same. So by reduction the gameplay is unchanged, and in a single bound I am free!
#515 posted by rj [86.0.166.158] on 2011/03/31 00:00:43
i seem to remember nehahra had some improved navigation systems for monsters, but you could always specify which one to use when placing the entity. i'd favour this approach
 AI 'smell' Trail
#516 posted by ijed [190.22.56.48] on 2011/03/31 02:23:22
Was something we were pondering. It got denounced when we mentioned it here of course.
Nehahra had various layers of AI and additional flags like INTREPID (ignore hazards when leaping off stuff) and the ability to teleport at will.
#517 posted by necros [99.227.131.204] on 2011/03/31 03:28:11
ai sounds like the most useful.
i've experimented with different methods but never really been satisfied.
currently, i'm using a sort of waypoint system that monsters will follow after they loose sight of your.
it has the benefit of making monsters look realistic when searching for you, but in some ways, it makes them less effective.
an interim system i have is to have the ability to flag path_corners to make monsters both not search for the player, not react to damage, and to use their run animation instead of walk when moving to them.
this is only useful for initial pathing, as once the monster is awake and not following path_corners, there's no benefit.
but yeah, a unified pathing system would be totally awesome, but i just can't see how to get it to work for all cases. :(
good luck though. i'd be really interested to see what you come up with!
A simple but useful bit of AI gameplay wise would be that melee monsters that are below the player or otherwise can't find a direct path to the player will instead seek to hide from the player's LoS (whether they could hide from grenades I dunno :P ).
This could help prevent a lot of cheesing combat, if the monster hides when the player is trying to pick it off from a safe position. It's often this which easily disarms the challenge in a lot of maps, and is why the only way to really create a challenging fight is just to suddenly drop the enemies directly on top of the player in a trap.
#519 posted by necros [99.227.131.204] on 2011/04/01 21:55:23
This could help prevent a lot of cheesing combat, if the monster hides when the player is trying to pick it off from a safe position. It's often this which easily disarms the challenge in a lot of maps, and is why the only way to really create a challenging fight is just to suddenly drop the enemies directly on top of the player in a trap.
i feel this is more a mapper's failing. you shouldn't really be letting melee monsters get into a position like that unless it's something you can't plan for (ie: fiend jumps off a ledge and can't reach you anymore).
but like, for example, you shouldn't really be able to 'pull' melee monsters from far away or don't provide an easy way to exploit them.
 Speaking As Primarily Not A Mapper...
#520 posted by Lardarse [62.31.162.25] on 2011/04/02 02:50:52
(...and no, this isn't an excuse to tell me to fuck off)
I'd contemplated re-writing the trigger system before, but I wasn't sure how best to do it. The way that makes most sense to me right now, is some sort of "message" system, that goes something like this:
"targetname" is what is being sent the message. The additional targetname entries (if present in the code) give it additional frequencies to be listening to.
"target" is what to send the message to. Again, the additional targets work like additional frequences to be broadcasting on.
And them there's an (as yet) unnamed 3rd field, which is the message to be sent. This could be something like a traditional use/activate signal, a kill signal, a change texture signal (so you can have brush entities that are doing something more useful than just being func_walls change their appearance), or maybe even something else.
This is made more interesting, of course, by being able to send a different signal to each target. Yes, this is still similar to how we have .target and .killtarget now (and yes, this would allow both to be done at the same time, as is the case in Quoth, RMQ, and other mods), but it would be more flexible than that.
The only part I'm not sure on, is if this signal should be a float or a string. And then, of course, you have to define what all of the signals mean for each object. Obviously, there would be a few common ones, but some would need additional things specified.
#521 posted by necros [99.227.131.204] on 2011/04/02 07:18:29
yeah, that's an ok system. it's good because it's unified and probably easy to understand from a programming point of view.
i imagine the 'message' could be a simple bit mask where you can select what you want to change to the triggered object. so a single trigger could change, for example, both the func_door texture AND open it or whatever.
but it's just easier to code up helper or script entities instead and more intuitive in an editor (not to mention there's no support for an 'entity message' in any editors).
#522 posted by necros [99.227.131.204] on 2011/04/02 07:21:07
mm, my mind apparently skipped a beat and i didn't actually explain myself on that third paragraph. o.0
i say it's easier, but it's also more flexible.
i have script entities that can change an entity's owner, change specific 'target' strings, toggle flags/spawnflags on entities.
toggling a func_walls texture is simple, but how would you put 'change targetname2 on this entity to xxxxx' in a simple one string/integer message. you'd end up with other helpers anyway.
 Collecting Sigils
#523 posted by Mike Woodham [86.185.201.19] on 2011/04/02 19:15:52
What is the code that lights the sigil's place marker on the player's GUI as each sigil is collected?
Are the lights just made in order or do the shapes relate to the actual sigil?
I do not get any lights when I use them (and collect them)in my levels - what gives?
 Sigils/rune
#524 posted by necros [99.227.131.204] on 2011/04/02 19:46:30
an engine coder could tell you for certain, but in the qc, picking up runes sets a global variable 'serverflags' with bits 1, 2, 4 and 8, corresponding to the appropriate episode.
the runes only work if the UI is set to the default one. hipnotic and rogue game modes turn on their respective UIs which don't check the runes. so if your mod uses one of those UIs or you're using quoth which uses hipnotic UI, then the runes don't show up.
 Mmmmm...
#525 posted by Mike Woodham [86.185.201.19] on 2011/04/02 20:57:11
Yes, if I use standard progs.dat (1.06) then the UI lights up. I am not using a mod but I am using an 'enhanced' progs.dat.
However, I have checked the sigil_touch section in items.qc and it exactly the same as the 1.06 version. I cannot find any other differences related to 'serverflags'.
Strange. Must be something, but I don't know what.
 WARNING: BAD CODE AHEAD
#526 posted by Preach [62.30.197.42] on 2011/04/02 23:44:24
THIS CODE IS PURE EVIL.
YOU MIGHT FIND IT USEFUL.
BUT DON'T GET FUNNY IDEAS.
So...I was working on the winner of the straw poll, which is the navigation entity stuff. Idea 3 did attract some attention so I might put up an article about naming in QC which would contain the "clever ideas" part of the event system I had in mind, so someone else with time on their hands would be free to do the footwork implementing it. Most of the effort would be in creating useful input and output on the various func_ entities, but at least it's a chance to exercise some creativity.
Anyway, I was trying to create some beautiful code involving callback functions (been reading too much ajax stuff recently) and managed to confuse the compiler enough for it to mistake a string field for a float. As you may or may not know string fields in QC are integer offsets into a big block of strings. So I came up with the following:
float INT_1 = 0.0000000000000000000000000000000000000000000014013;
.string tempstring;
void(.float stringfield) increment_string =
{
float increment, stringvalue;
increment = INT_1;
if(self.stringfield < 0)
increment = increment * -1;
stringvalue = self.stringfield;
do
{
stringvalue = stringvalue + increment;
increment = increment * 2;
}
while(stringvalue == self.stringfield);
self.stringfield = stringvalue;
}
void(void(.string floatfield) dispatch, .string fieldtype) strip_fieldtype =
{
dispatch(fieldtype);
}
//then put the following code somewhere
{
self.tempstring = self.model;
while(self.tempstring != "")
{
strip_fieldtype (increment_string, tempstring);
dprint(self.tempstring);
dprint("\n");
if(self.tempstring == ".bsp")
{
dprint("It's a bsp file!\n");
break;
}
}
}
It's so hacky I don't even want to talk about why it works.
 Shamefaced
#527 posted by Preach [62.30.197.42] on 2011/04/03 00:44:19
In time maybe I'll see this as undoing a great blessing but: a correction:
float INT_1 = 0.00000 0000000000000000000 00000000000000 00000014013; but without the spaces.
#528 posted by necros [99.227.131.204] on 2011/04/03 07:04:57
increment = INT_1 o.0
mike: i was referring to the command switch you use when launching quake, not the progs. the progs can't change the UI itself, unfortunately. if you put hipnotic progs in the id1 folder, you'll get hipnotic entities, but the UI will be default quake.
 Oh Btw
#529 posted by necros [99.227.131.204] on 2011/04/03 07:19:54
on pathfinding...
if you're gonna implement a brand new system... should just go whole hog and do a star and just let the mapper plop down some nodes. that'd be insanely badass...
i'd totally do it, but i'm too dumb. ^_^
 Necros
#530 posted by Mike Woodham [86.185.201.19] on 2011/04/03 10:07:54
I am not sure I understand. No, I am sure I don't understand.
I have two .bat files:
fitzquake085.exe -window -heapsize 40960 +gl_clear 1 -width 1024 -bpp 32
fitzquake085.exe -window -heapsize 40960 +gl_clear 1 -width 1024 -bpp 32 -game mynewprogs +skill 2 +map This_FMB_1_8c
The first runs the iD1 folder and this has no qconsole file and the same config file as the mynewprogs folder. The mynewprogs folder does not have a qconsole file either.
As far as I can see the only difference in the two folders is the progs.dat. Yet the first bat file game shows the runes lights as you pick them up but the other bat file game doesn't.
It does not actually affect the gameplay but as you need all four runes to create a certain effect, it would be useful for the player to able to see what he has already picked up instead of having to remember.
Any hints as to what could cause mynewprogs to apply different UI settings?
 Itemized
#531 posted by fakepreach [86.129.223.59] on 2011/04/03 17:40:53
So do you have .float items2 defined somewhere in your code? If it is defined anywhere then the serverflags info is not sent to the client - to save bandwidth that info is replaced by the items2 info instead.
 Fakepreach
#532 posted by Mike Woodham [86.185.201.19] on 2011/04/03 18:43:06
Funny you should say that. Yes, I do have .float items2 as I have the drole and vermis from Quoth.
//quoth -- items
.float items2; // bit flags for new items -- ran out of room on items...
I am not sure why they ran out room; perhaps I'll experiment with changing it to 'items' and see what breaks.
 Runes Can Exist In .items2
#533 posted by Lardarse [62.31.162.25] on 2011/04/03 21:15:52
As 32, 64, 128, and 256. If you're using .items2 for your own nefarious purposes, then leave those four bits for the runes.
 Note That
#534 posted by Lardarse [62.31.162.25] on 2011/04/03 21:22:25
sigil_touch() will need to be adjusted for this to work. The line
serverflags = serverflags | (self.spawnflags & 15);
should be followed by
other.items2 = other.items2 | ((self.spawnflags & 15) * 32);
This won't send the update to all players, but that's only relevant in coop. Also, impulse 13 won't update the hud properly, but a similar line will work in the function that handles it.
 Ohh
#535 posted by necros [99.227.131.204] on 2011/04/03 21:55:22
thanks fakepreach and lardarse for clearing that up! i had no idea .items2 had any bearing on serverflags!
mike, since you're only using the drole, you could do a quick find/replace and just change 'items2' to something like 'drolevar'.
that way you can just leave the old serverflags variable alone.
 Thanks Necros, Fakepreach, Lardarse
#536 posted by Mike Woodham [86.185.201.19] on 2011/04/03 23:25:42
As I am not using any Quoth items, I can do away with the code relating to items2 without any detriment. It's just a couple of If/Then statements which don't apply anyway.
Onwards and upwards...
#537 posted by necros [99.227.131.204] on 2011/04/04 00:12:42
don't forget to tone down the drole damage a lot. ^_^;
 Drole Damage...
#538 posted by Mike Woodham [87.127.250.2] on 2011/04/04 09:54:53
"Do you expect me to talk?"
"No, Mr Bond. I expect you to die!"
 Bbox Sizes
#539 posted by necros [99.227.131.204] on 2011/04/20 07:34:14
so, going in the opposite direction, it's possible to make monsters with smaller bbox sizes, however you need to offset them by whatever amount smaller than 6 that you used.
now that you're down frowning in perplexity at that terrible sentence, this is what i mean:
say you made a skinny monster, '-6 -6 -24' to '6 6 40'
you need to setorigin(self, '-10 -10 0') the monster or, if you place it close to walls, it will get stuck (even though, when you turn r_showbboxes on, the bbox clearly is not in any wall).
but other than that, it seems to work fine, really lets monsters bunch up. would have worked good for the voreling had i known about it back then.
 Heh
#540 posted by necros [99.227.131.204] on 2011/04/20 07:35:02
not only was that sentence awful, but there's a typo too.
by whatever amount smaller than 16 that you used.
#541 posted by metlslime [67.188.81.46] on 2011/04/20 07:55:21
I did this with Floyd, didn't do the setorigin trick but instead made the in-editor box full shambler size so there's no risk of placing it in a wall.
 Fools Echo
#542 posted by madfox [84.26.69.4] on 2011/04/20 21:15:25
I'm still perplexed in making the Doomguy crouch.
Didn't want to start it over afraid of being a fool.
But the trick me was told to lower the bouncingbox so bullits would fly over it, and then raise the model again.
I don't understand. Then it would sink in the ground, but raising it would raise the bouncing box too?
#543 posted by necros [99.227.131.204] on 2011/04/23 21:38:08
i'm not sure if we've covered this but when do touch functions get run when monsters are involved via movetogoal/walkmove?
are they run at the moment movetogoal is called?
ie:
void() someTouchFunction =
{
other.happy = 0
}
void() ai_run =
{
self.happy = 1
movetogoal(1)
if (self.happy)
cheer
}
so in this retarded example, while the ai_run function will make the monster happy, it will run a touch function right after movetogoal so that the if statement will fail?
i've been observing some screwed up behaviour and i'm trying to track it down...
 Touchy Subject
#544 posted by Preach [86.129.223.59] on 2011/04/24 11:19:43
Yeah, the touch functions are respected there - only pitfall to bear in mind is that if the move fails because the monster is blocked, then they don't move at all and so the monster doesn't touch.
So that doesn't really help you track down your problem, and it sounds like you've got a pretty solid minimal test there. So I'm just gonna take a peek at somet-
OH MY!
Oh dear.
Very long standing bug in quake coming right up...
PF_walkmove, the non-navigational monster moving code, has the following code in it, which I remember noting down for possible use with that JS quake engine idea
// save program state, because SV_movestep may call other progs
oldf = pr_xfunction;
oldself = pr_global_struct->self;
G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
// restore program state
pr_xfunction = oldf;
pr_global_struct->self = oldself;
Firstly a quick note, "PF" in front of a function in the quake source means that it's a "progs function" - a light wrapper around some C code called as a QC builtin. The snippit I quoted then calls SV_movestep - the real heavyweight movement function which other parts of the engine also use.
Around that call we have some clearly documented code which stores the current QC execution state and restores it after the call. This firstly tells us that touch functions are a possibility they have programmed for, and secondly eliminates a possible source of the buggy behaviour - that after calling the touch control never returns to the QC.
Except your QC doesn't use walkmove, it uses movetogoal. I went looking for PF_movetogoal and was surprised to find it missing. It turns out that the QC builtin in this case directly calls SV_movetogoal instead, and I'm sure some of you are ahead of the puchline here - it doesn't save the QC state.
I haven't gone away to do follow up QC tests, but worst case I can imagine is that none of the remaining QC in your function ever gets run if a touch function is encountered, and best case is that it's just self that gets obliterated. In the former case you are basically stuck with using walkmove instead. In the latter you can put the traditional
local entity oself;
oself = self;
movetogoal(1)
self = oself;
But yeah, genuine nasty bug there I think. Let me know whether it is that worst case scenario situation or what, I'd like to know...
#545 posted by necros [99.227.131.204] on 2011/04/24 19:23:58
ohhh ok, yes! that explains some OTHER whacked out behaviour i've been seeing!
i've changed movetogoal into a wrapper that (among other things) does a movetogoal(1) and then calls x number of walkmove(directionItMoved, 1) to complete the amount of movement requested.
this allows a monster to continue to move forward, even if it's full movement would have failed allowing it to get through thin or cluttered areas better.
i was seeing some weird stuff where a monster would touch a trigger and then not move (it was moving by 1, but not completing the walkmoves).
i guess it never mattered before because movetogoal was solely called at the very end of a qc function.
anyway, i've added in your suggested change and will test it today. :)
 Binary Chop
#546 posted by Preach [86.129.223.59] on 2011/04/24 21:09:23
If you like, there's a trick you can apply there to only call ~log(x) steps in the worst case rather than x for moving x distance.
The trick is try to walkmove(x) first - being optimistic!
Check the return value for failure, and we can finish if we succeeded.
If we failed, replace x by with x * 0.5. We then try to walkmove(x) with the new x.
We keep repeating the above step(in italics) until x is smaller than 1.
Note that after the first iteration we don't need to check for success.
Worked example:
Suppose we want to walk forward 32 units but only have space to move 21 units.
First time through walkmove fails
x=32, moved=0
Second time through we succeed
x=16, moved=16
Third time round we fail as we are 16 forward and another 8 would take us past 21
x=8, moved=16
Fourth round we succeed
x=4, moved=20
Fifth fails
x=2, moved=20
Sixth succeeds
x=1, moved=21
Since x has reached 1 we terminate.
I'm making the numbers quite friendly by choosing x as a power of 2. It also lets me gloss over the edge cases of when to reject x and stuff. Nonetheless the method is sound and a fairly simple loop. Probably the hardest idea would be proving that it always works, I've always been fond of Proof by Single Worked Example though...
 Yeah
#547 posted by necros [99.227.131.204] on 2011/04/24 21:23:21
i've been meaning to do that. :)
i wasn't sure if there was a point where doing it linear was faster or if it was always slower and i just haven't been in the mood to try to figure it out. ^_^;
it looks like you're saying it's always faster?
also, while we're talking about walkmove and such...
is it ok to call a walkmove/movetogoal larger than bbox size?
ie: walkmove(yaw, 256) as opposed to looping walkmove (16) 16 times.
not sure if this messes up collision if the bbox is displaced by huge amounts...
 Empirical Answers
#548 posted by Preach [86.129.223.59] on 2011/04/24 22:44:06
Yeah, the binary chop should always reduce or equal the number of calls to walkmove in the linear algorithm. The nice thing about it is getting twice as high precision only costs you 1 more call to walkmove, although I doubt anyone needs monsters THAT much more finely tuned than 1 unit.
I tried to pick through the engine code to decide if you could get away with long distance walkmoves. But it's the densest part of the engine code and although my suspicion was that collisions would get skipped I wouldn't be able to answer with confidence.
So I bashed away through the latter half of Lewis and made a test mod. The emperical conclusion: no.
You can make a monster walkmove 256 units and completely skip a 64 unit trigger. So yes, limit yourself to width of a bbox per iteration. You can be assured that you won't ever skip through walls of the game world. BSP entities don't count though...
#549 posted by necros [99.227.131.204] on 2011/04/24 23:48:57
You can be assured that you won't ever skip through walls of the game world.
this is more what i was asking. mainly the use for super long walkmoves would be to check for charging/leaping abilities like fiends instead of just checking if they can see the player.
a walkmove check of even just 16 or so units will stop a fiend from doing that psycho leap 'bug' around doorways.
otoh, it will also cause it to fail more often as a jump that would hit a wall yet allow it to bounce towards the player (and hit him) would fail unlike with just plain visibility checks.
you could possibly make a 'robust' walkmove that, when failing to move, would tweak angles by a small amount and try again.
hmmm...
 Rollback
#550 posted by Preach [86.129.223.59] on 2011/04/25 01:15:14
I was about to warn you about using walkmove checks(where you want to reserve the right to rollback the movement and do something else) too freely. What if you walkmove into a rocket during a 'check'. Luckily you are largely protected from this kind of thing. This is because the only thing that monsters will collide with during a walkmove or movetogoal is SOLID_TRIGGER entities.
So really all you need is to watch your triggers which respond to monsters when you're doing that kind of thing. In standard quake that's only really telefrag and trigger_hurt - which you could guard against with a quick change of takedamage.
If you really get into that kind of thing you can go down the route of having a 'proxy' entity instead. I was trying to think about what you'd need to do to get the proxy perfect. The think you'd need to get right is .owner, which would take 3 transformations:
1)Set the owner of monster's owner to the proxy.
2)Set the owner of proxy to the the monster.
3)Set the owner of everything else in the world currently owned by monster to proxy.
You also need to store enough information to reverse all these changes.
This is of course absurd levels of effort. Just set the proxy's owner to the monster, and accept that occasionally it'll be blocked by an entity that owner settings would have let the monster walk through. Never realistically a problem.
#551 posted by necros [99.227.131.204] on 2011/04/25 01:20:10
thanks, i hadn't thought about the 'premature triggering'. yeah, a proxy looks like the best bet.
when i needed a walkmove check to move through monsters, i just set all monsters to non-solid. :P
#552 posted by necros [99.227.131.204] on 2011/04/25 01:20:43
or a flag on the entity you toggle on temporarily that you code into all triggers 'don't activate when this flag is on'.
 Addendum
#553 posted by Preach [86.129.223.59] on 2011/04/25 01:25:44
The takehome message of the last post is:
During a walkmove or movetogoal the monster will only collide with SOLID_TRIGGER entities.
I want to add that only the trigger's touch function is activated, the engine does not call the monster's touch function with the trigger as other.
 In Error
#554 posted by Preach [62.30.197.42] on 2011/05/01 22:59:30
So I adapted the code which I wrote last week answer that question about movetogoal. It turns out that even through touch functions, it restores the QC state correctly and doesn't overwrite self. This is admittedly run from a think function - it's possible that you could create a more complex scenario like calling movetogoal from a touch function and then causing another touch function.
But I thought I'd share it with you because it made me practice a few diagnostic tools for QC, some of which you may not be aware of.
The first is just chucking in a load of dprint statements, I'm sure most people have done that before. Don't forget that you can use ftos() and vtos() to put more information into the statements. If you need to confirm the value of an entity variable (as I wanted to with self) you can use the eprint() function instead.
The second tool is a bit of a hack. It allows you to get a stack trace. This was particularly valuable in this case because of the concern that the touch function might be trashing the stack. But it would be of use in any case where you have an interaction between think and touch functions causing a bug, and you want to know what is calling what.
There's no command or QC builtin for a stack trace, but you get one if you manage to perform an invalid operation in QC. The infinite loop is one way to do this, but personally I prefer the null function call, it's a bit quicker. Just throw something like
world.think1();
and unless the map is particularly weird you'll get your error. Of course, this does shut down the entire server, so it's not for general use.
The last trick is pretty powerful but also has the potential to spam the entire console out. The QC builtins traceon() and traceoff() allow you to enable console output of every Qasm instruction that the server reads - including the register values that were employed.
I believe Qasm is a neologism, and if so I demand it be pronounced as "chasm". It refers to the bytecode that a QC compiler creates - effectively Quake Assembly code. You can use one of the options in FTEQCC to output the assembly to a file, which is a good way to learn what the trace output means.
(As an aside FTEQCC also lets you enter segments entirely in Qasm. This is in the same way as c compilers accept asm segments - and indeed the original quake engine did just that in the renderer to get tight loops fast enough for the Pentium 75s to run the game. I believe most modern ports strip the assembly out. Even so, in quake Qasm is a great way to do naughty things that the compiler won't let you...)
 Are You Sure?
#555 posted by necros [99.227.131.204] on 2011/05/02 00:29:27
because i distinctly remember after putting in the self restoration bit that it fixed a problem with walkmoves not being called after movetogoal.
 Yeah
#556 posted by Preach [62.30.197.42] on 2011/05/02 01:06:07
We might have to share some code here to determine why we're getting different results. If you whack an eprint(self) in before you restore self do you get the trigger entity that you touched come up?
 Heh
#557 posted by necros [99.227.131.204] on 2011/05/02 02:37:38
yeah, i guess i could have at least tried it out to see.
you're right, self isn't being lost when touching triggers. trying to figure out now would be pointless though, because the code has change by a huge amount since last time i posted about it.
 SV_TouchLinks: Next != L->next
#558 posted by necros [99.227.131.204] on 2011/05/08 20:20:10
is it bad to call setorigin(self) in a touch function? does that cause the touchlinks warning in fitz?
i googled the forums, but i don't think it was ever really explained what this error is, only that it used to crash in e2m2.
 Potentially
#559 posted by Preach [62.30.197.42] on 2011/05/09 00:29:39
I'm not brilliant at following how the engine handles this touch stuff, but here goes:
The following functions could cause problems with sv_touchlinks:
setorigin
setsize
droptofloor
movetogoal
walkmove
All these functions can cause the entity to be relinked, which potentially causes the issue. There are some other conditions that need to be met before the error is encountered: firstly the entity has to be part of the same areanode as the touch is coming from*. My understanding is that there are 32 areanodes in a map to reduce the number of entities considered in the collision code by approx. that factor.
The other important thing is that the entity has to actually break the chain of linked entities at exactly the point that sv_touchlinks is operating. I believe that this translates to applying any of the dangerous functions to other, but again not too sure how all the code fits together.
A final small point is that even if do apply one of the dangerous functions to other (and since we're in a touch function with other it's safe to assume by now that they share an areanode) we might still get away with it. This case would occur when other is the first entity in the areanode - relinking it will reinsert it in the same place as before. There's no safe way to exploit this though, as it's determined entirely engine-side.
The last thing to remember is that sv_touchlinks only looks through the list of triggers, so anything that's not SOLID_TRIGGER* ought to be safe. Best of luck!
*Technically that should read "that wasn't SOLID_TRIGGER last time the entity got linked into the world" but that's a bit of a mouthful. All that means is that you can't quickly set the entity to SOLID_NOT and get away with anything, it's about whether the entity is truly a trigger according to the engine at that time...
 Footnote
#560 posted by Preach [62.30.197.42] on 2011/05/09 00:31:10
That first asterisk should have been removed, the footnote is about the SOLID_TRIGGER statement - though most of you spotted that anyway I expect...
#561 posted by necros [99.227.131.204] on 2011/05/09 00:54:07
yeah, this is happening with some of my code. unfortunately, i have the report from a third party and haven't been able to reproduce it myself. apparently, occasionally, it spams the console with sv_touchlinks errors in fitz085.
i noticed this tiny comment in defs.qc for setmodel:
void(entity e, string m) setmodel = #3; // set movetype and solid first
and i checked that entity and found that i was setting self.model before movetype. so i fixed that anyway, but maybe that might also have been the problem? the entity wasn't properly linked in the first place?
geez, i dunno. :P
it's supposed to be a visible solid_trigger entity that changes origin when you touch it.
i was wondering, maybe if i used to bad method of just setting self.origin in the touch function, that way, it's not breaking whatever links?
 Danger
#562 posted by Preach [62.30.197.42] on 2011/05/09 09:11:32
From what I've gleaned, that is the most dangerous thing you could do in a touch function, although I didn't post it correctly. I was talking about the danger of moving other, but I should have been talking about self. I had the two muddled up and I'm sorry about that.
The standard way to cope with this is to set up a quick think function from the touch function, and have that think reset the origin. You can put a guard into the touch function to prevent multiple touches before it moves - set up a flag on the entity and toggle it in the touch and think.
 Hm Ok
#563 posted by necros [99.227.131.204] on 2011/05/09 20:57:07
so what i can do is just set a flag after the touch function to disallow further touches until the think function has been run. that should work i guess. a little roundabout but last thing i want to do is start causing crashes. :P
 Speed-up
#564 posted by Preach [62.30.197.42] on 2011/05/09 22:19:31
You can also use a little trick to make sure the think function runs as soon as possible (either this frame or the next). Just set self.nextthink = 0.05; - note that we are deliberately omitting time from the assignment. Since this will be in the past for every frame the engine runs (frame 1 runs at time = 0.1) it will execute the think as soon as the entity is checked by the engine.
The flag works a bit like the way that
if (self.nextthink > time) line works for a trigger_multiple, so if you don't want to use another field that approach is an option. My feeling is that the flag is simpler because you don't need the flexibility of a custom delay but it's basically a preference thing.
 Spot The Deliberate Mistake?
#565 posted by Lardarse [62.31.162.25] on 2011/05/10 19:59:18
(frame 1 runs at time = 0.1)
Time starts at 1, not 0. This is one of the quirks of the system, that makes very little difference, except for when it trips you up (and when it does, it hurts). For example (from the id1 code):
self.nextthink = self.nextthink + random()*0.5;
This line appears in all of the $foomonster_start functions. The original intention was for monsters to not all do their setup on the same frame, to reduce computer load. However, what actually happens, is that on a roughly 1 in 32000 chance (or, according to LordHavoc, 1 in 2 billion on Linux), self.nextthink is set to 0, which means that it never thinks again (as .nextthink is set to 0 before the think function is called), and the rest of the time, it happens on the next frame.
 Thinking About The Other One
#566 posted by Lardarse [62.31.162.25] on 2011/05/10 20:00:41
When a think function is being called, what is other set to? Does it get set to something predictable, or is it just left as whatever it was last time?
#567 posted by necros [99.227.131.204] on 2011/05/10 20:30:38
so that bit of code doesn't actually do anything then?
might be a good idea to change to it 1 + random() * 0.5 then? because that must mean thinks are being all processed on the same frame.
also, on other, a few think functions steal other for their own uses so even if it is being reset every frame, you might get a semi-random entity if one of those thinks happened during the frame?
 I'd Say
#568 posted by SleepwalkR [85.178.188.171] on 2011/05/10 22:05:58
(1 + random()) * 0.5
#569 posted by necros [99.227.131.204] on 2011/05/10 22:09:03
won't that still generate nextthinks < 1?
 Depends
#570 posted by SleepwalkR [85.178.188.171] on 2011/05/10 22:11:59
Is nextthink a float or an int, and how do conversions work in QC? If it is like in C, then yeah. I just thought it's closer to the original, but heh we don't really want that.
 <1
#571 posted by Preach [62.30.197.42] on 2011/05/10 22:42:23
It's ok to generate thinks which are less than 1 in this case, because as long as it's non-zero the think function will run, and you'll still spread the monsters out over many frames because not all of them are going to get the same random number.
And if they did, they'd all be set off on the same frame no matter what function you did...
Good catch on the server starting at 1 there though, I must remember that. Either way, as long as you don't set nextthink to 0, any value less than 1 will give you the soonest think function possible.
 However
#572 posted by Lardarse [62.31.162.25] on 2011/05/11 00:41:39
any value less than time will give you the soonest think function possible
As Spike has pointed out a few times, when a think function is called, for that dive into the code only, time is set to what .nextthink was before being reset. So the most reliable way for a "do this next frame" is probably self.nextthink = time;
 Well
#573 posted by Preach [62.30.197.42] on 2011/05/11 00:52:53
Only if your code depends on the value of time in some way. If all you need is for it to run in the next server frame then you can take the shortcut. If time cannot every be less than 1 then a value less than 1 is always less than time...
#574 posted by necros [99.227.131.204] on 2011/05/11 01:27:20
i think it's more about successive thinks.
the less aligned monster thinks are, the less impact the ai routine has when it's run, i would think.
if you just set nextthink to 1, every monster will be thinking at the same time.
 Shadow Casting Bmodels
#575 posted by necros [99.227.131.204] on 2011/05/14 23:03:56
could someone modify MH's Aguirre's light utility so that it casts shadows from bmodels?
and maybe a new key '_noshadows' to disable shadows on that particular bmodel?
or is it not possible? like bmodels can't be used for some reason?
 Reversal Of Fortune
#576 posted by Preach [62.30.197.42] on 2011/05/15 02:00:54
Not commenting on how it can or can't be done, but I'd recommend making it opt-in rather than opt-out. Having an entity key _castshadows which you set to 1 to enable the new function would keep the current behaviour on existing maps, which is always desirable when possible. I also think there's a good chance that the cases you don't want it on (entities which move or have little to no impact on shadow casting) outnumber the entities which would benefit. It would make it reactive - used only when the lighting looks wrong - but I don't think that's a bad thing.
#577 posted by necros [99.227.131.204] on 2011/05/15 02:05:40
maybe. either way, it'd still be great if someone could haxor that in. :)
#578 posted by necros [99.227.131.204] on 2011/05/21 01:45:14
we were talking about how bsp models use their bboxes to figure out collision a little while ago.
i mentioned about setting bbox in qc affecting that. i tested it out, and yes, if you manually set bbox size, you can don't need to put visible brushes at the min/max extents.
also, if there are visible parts of the bsp model but the bbox is smaller, any bits outside the bbox are nonsolid.
 Award
#579 posted by Preach [62.30.197.42] on 2011/05/21 10:02:36
also, if there are visible parts of the bsp model but the bbox is smaller, any bits outside the bbox are nonsolid.
Hack of the week right there, folks. Awesome!
 Backup Past 0
#580 posted by necros [99.227.131.204] on 2011/05/30 00:15:26
what the heck is this anyway? :P
 Tracing Error
#581 posted by Preach [62.30.197.42] on 2011/05/30 11:42:39
It's a glitch in the trace code. It arises in the part of the code that tries to determine the exact impact point of a trace on a solid surface. The loop starts with a point at "0" which it knows is in the open, and a midpoint which it knows is in solid BSP. It then backs up from the solid point in small increments until it gets into the open, and so fixes the endpoint of the trace.
The glitch occurs because the increments don't always exactly hit the 0 point as they build towards it. It is possible for the trace to be in solid for all of the test points before 0, and for the increment to never hit exactly 0. The loop would then return the first point past 0 as the nearest point-in-open to the impact point(i.e. backup past 0). However, we already know that 0 is closer to the surface and in-open so that point is returned instead.
Phew, so basically I think this is most likely to occur on short traces where an endpoint is near a surface, as these are the traces where floating point inaccuracy is most prevalent, and I believe that makes a difference. However, there is a binary chop portion of the trace algorithm, so the circumstances that cause it to happen may just occur at random on any given surface.
Possibly also complicated or intricate BSP architecture could make this more likely, since you would have to dive down to a smaller scale to check exactly which bit of fine detail a trace collides with, but I've got no example to back that up with.
 Thanks
#582 posted by necros [99.227.131.204] on 2011/05/30 19:38:35
that helps a lot to know at least what is causing it.
 Sounds...
#583 posted by Mike Woodham [109.156.194.239] on 2011/05/30 20:36:49
Sounds don't start until one second after worldspawn. Is this 'fixable' from qc?
My FMB_BDG map finishes with an earthquake and it would be nice, from a continuity point of view, to start the next section with the tail-end of the earthquake.
 Time Starts At 1, Not 0
#584 posted by Lardarse [62.31.162.25] on 2011/05/30 21:46:32
So it's probably fixable from the map(s).
 Sound Out
#585 posted by Preach [62.30.197.42] on 2011/05/30 22:05:41
Completely untested, but if you spawned a static sound which didn't loop, does that cause an error? Otherwise it might just get around the problem...
 Oh Yeah
#586 posted by Preach [62.30.197.42] on 2011/05/30 22:07:21
that helps a lot to know at least what is causing it.
Probably the most important thing to know about it is that it doesn't matter at all - there's nothing going wrong in your code and the engine has already coped with the potential inadequacy. So I'm not even sure the message is worth preserving in the engine...
#587 posted by necros [99.227.131.204] on 2011/05/30 22:25:06
well, if there's no purpose to it... i just get spammed by it sometimes and it clears out the console buffer of useful debug text, which is annoying. good to know it isn't causing problems.
also, trying to spawn a static (ambient) sound that isn't looped results in that 'sound isn't looped' error we used to get with the broken ambient_thunder entity.
#588 posted by necros [99.227.131.204] on 2011/06/12 21:24:22
i have a bad feeling about this but....
is there ANY way to detect if the player has either opened the menu or closed it?
 Unlikely
#589 posted by Preach [62.30.197.42] on 2011/06/13 00:04:18
I can't see how you could, no QC runs while you're in the menu (assuming you're thinking of single player - multiplayer is different but no more helpful). You'd end up trying to spot differences from frame to frame in the same way that QC detects loading from a saved game. The problem is that you could quite easily go into the menu, do nothing and then leave after a while. I don't see how this would leave anything for the QC to find...
#590 posted by necros [99.227.131.204] on 2011/06/13 01:39:19
yeah, i was afraid of that. :(
oh well, thanks anyway.
 Monster_decoy
#591 posted by jt_ [24.11.39.160] on 2011/06/17 04:30:21
What was this used for in SoA?
#592 posted by necros [99.227.131.204] on 2011/06/17 04:56:00
cutscenes. it's a player model that will run to path_corners and wait for a few seconds, if 'wait' or 'delay' or something is set.
iirc.
 Ah, Thanks.
#593 posted by jt_ [24.11.39.160] on 2011/06/17 05:05:43
 Func_areaportals
#594 posted by jt_ [68.42.82.10] on 2011/06/21 02:10:01
Has anyone ever tried porting func_areaportal from quake 2 to a quake 1 engine and related tools? Any idea on how hard it would/wouldn't be?
#595 posted by jt_ [68.42.82.10] on 2011/06/21 21:45:30
So I've been thinking about a way to add a lot of new weapons to a mod, but I'm not sure about some things. The first issue would be how the hud handles the weapons, since there's only enough room for 9 weapons, I would need to figure out a way to make sure that weapons don't take each others spots. I was thinking of adding a precache variable to each weapon and then checking to make sure that none of them conflict with each other when the map starts. I think that would eliminate the problem of weapons taking other weapons spots. I have no idea how and for what reason they're placed on the hud the way they are, anyone have any insight on this?
 HUD Placement
#596 posted by Preach [62.30.197.42] on 2011/06/21 23:50:38
There's actually quite a lot to be said about the HUD but I'll try and get the basics into one short post.
The engine uses the QC field called items to determine which weapons to display on the HUD. If you look in defs.qc you will find the following:
// items
float IT_AXE = 4096;
float IT_SHOTGUN = 1;
float IT_SUPER_SHOTGUN = 2;
float IT_NAILGUN = 4;
float IT_SUPER_NAILGUN = 8;
float IT_GRENADE_LAUNCHER = 16;
float IT_ROCKET_LAUNCHER = 32;
float IT_LIGHTNING = 64;
To display some collection of these items on the screen simply sum the values of the icons you want displayed, and then set self.items to equal the total.
The numbers are all carefully chosen as powers of 2. This is useful because it makes any sum a unique combination of these numbers. It also means that you can use the bitwise OR function to safely add an item without checking if it is already there:
self.items = self.items | IT_SHOTGUN;
If we started with 0 items, and then blindly added IT_SHOTGUN to self.items we might get into trouble - if that line of code ran twice then self.items would equal 2 and we'd have IT_SUPER_SHOTGUN instead.
We can also use the bitwise AND function to test if an item is present:
if(self.items & IT_NAILGUN)
{
//do something just for players with a nailgun
}
If the bitwise functions are new to you I'd advise searching for a c tutorial on them, it's probably been explained before in a clearer way than I'd invent today.
Other things to know about icons:
• Setting self.weapon to one of the IT_ values highlights that icon as the selected weapon.
• The mission packs added extra weapons which complicate the icons code somewhat, so I'll avoid that until another day.
• The engine automatically makes new items blink on the HUD when they are added to self.items.
 Path_corners
#597 posted by jt_ [68.42.82.10] on 2011/06/29 17:13:57
I made some path_corners in a map that are different z distances (hight/lower than another path_corner) apart, thinking that my flying monster would follow them. To my surprise, it didn't. After removing the z distance from my path_corners, the monster follows the path just fine.
It seems that with flying monsters, if path_corners are different z distances apart, they 'ignore' the path_corners. From a brief look at the quakec, everything looks ok. Maybe this is a bug in PF_walkmove? Looking at the function, it looks like it ignores the z axis all together (line 28), so maybe it's not a bug, Carmack just ignored it :p.
Note: This doesn't affect walkmonsters (as much) as flying monsters. With walkmonsters, they seem to be able be able to find their next path_corner as long as the z distance between them isn't too much (I haven't found out exactly what it is).
Looking a monsters.qc at the walkmonster_start_go and flymonster_start_go functions, and more specifically at if statement testing if there's a target, walkmonsters set their .ideal_yaw to vectoyaw(self.goalentity.origin - self.origin), flymonsters don't do this. I have no idea if that statement is related to the problem, correlation does not imply causation. :)
I need to fresh up on my trig..
#598 posted by necros [99.227.131.204] on 2011/06/29 20:52:34
it is a bug with movetogoal.
movetogoal does not check z unless both .goalentity AND .enemy is set.
if .enemy is set to a path_corner, it actually will track vertically. unfortunately, this necessitates a qc change.
ALSO, if you can believe it, THIS SAME FUCKING BUG IS PRESENT IN DOOM 3. CARMACK. COME ON MAN.
you will not believe the incredulity i felt when i set up a nice path for my cacodemons only to have them not able to fly up or down to reach them, even with AAS computed.
 Oh Also
#599 posted by necros [99.227.131.204] on 2011/06/29 20:54:43
walkmove explicitly does ignore z but it is only a simple 'step in this direction' function.
the function you want to look at is the movetogoal one, which does the random monster bumping around stuffs and probably contains the vertical adjustments for flyers when chasing enemies.
 Necros
#600 posted by jt_ [68.42.82.10] on 2011/06/30 01:23:14
Upon reading your posts, I naively added ``self.enemy = self.goalentity'' right after path_corner check in *monster_start_go functions in monsters.qc, thinking that it would fix all of my problems. Now the monsters are facing towards the path_corner and are in their walking animation, bit they're not moving at all. D: I suspect this has to do with a change I made, as I've been adding a lot of new things and haven't been testing any of them :p. oops.
Now 'all' I have to do if find what the problem is..
#601 posted by necros [99.227.131.204] on 2011/06/30 02:27:22
you will need to haxor it in.
basically, in ai_walk, change:
movetogoal();
to
self.enemy = self.goalentity;
movetogoal();
self.enemy = world;
or alternatively, create a movetogoal wrapper only for walking:
void(float step) walktogoal =
{
self.enemy = self.goalentity;
movetogoal();
self.enemy = world;
}
and just replace movetogoal calls with walktogoal in ai_walk.
the wrapper method is probably cleaner and if you make new walking functions, you don't need to repeat the hack.
 Remember That
#602 posted by Lardarse [62.31.162.25] on 2011/07/02 17:52:49
movetogoal() also needs the distance.
 Ragged
#603 posted by madfox [94.215.210.233] on 2011/07/15 03:23:58
I'm trying the shield code for the EldenOgre, but I'm not lucky.
I found some arg in the qc I couldn't place, or I should look at the pentagram code but I couldn't trace it.
OLDONE.QC - line 271 => self.takedamage = DAMAGE_YES;
OLDONE.QC - line 138 => pl.takedamage = DAMAGE_NO;
So I thought to be smart by adding it to the shielding frames like:
void() xogre_shield4 =[ $shield4, xogre_shield5 ] { self.takedamage = DAMAGE_NO;};
This works, but now I can't stop it shielding!
Another thing is the line in Defs.QC
DEFS.QC - line 443 => .void() th_defense; // gb, need to defend against enemy fire
The oldone.qc is the only one with the th_defense in it.
Can I use it on an entity?
Maybe a weird question for someone who knows how the code DOES work, butI thought making an entity shield is something like giving it a Pentagram?
It's not Quake related, but anyone up for helping me with a SAT based collision detection issue?
 Madfox
#605 posted by gb [46.142.11.117] on 2011/07/17 21:53:27
th_defense is an RMQ specific AI extension.
Look in ai.qc under ai_defensecheck(). If a monster's self.enemy just fired a weapon, the monster does whatever is defined in its th_defense function.
In the case of the shield ogre, it does xogre_defense() which is calling the shield animation etc.
It also sets self.shielded to 1 (in the shield frames), which is checked in turn in weapons.qc. That is where the actual projectile reflection stuff is done.
xogre is the only monster with a defined defense behaviour atm; however, you can use self.th_defense on *any* monster in RMQ. Just need to make a mymonster_defense function that contains the defensive action. If the monster's defense requires some extra jazz, like projectile reflection, add that to weapons.qc.
All of this requires RMQ.
If you want to do this in your own progs.dat, just port the ai_defensecheck(), self.shielded and all related stuff to your codebase.
I'm pretty sure Supa wrote the actual projectile reflection code in weapons.qc, so ask her (on the trac) if you need help with that.
All of this is really pretty RMQ specific stuff. Monsters actually defending against attacks is something that's still work in progress.
 Thanx Gb, For Your Explaination
#606 posted by madfox [84.26.185.158] on 2011/07/17 22:41:47
I've been looking at the RMQ code, but as the normal QC.108 is already over my hat I thought to look at the normal monstercode.
The th.defense I found in Defs.qc and as I couldn't find it elsewhere I wondered where it could relay to.
I tried earlier to calculate the code in but when I used te RMQ code it started stuttering on other args.
 Ambush
#607 posted by jt_ [68.42.82.10] on 2011/09/06 02:48:47
Does the engine cause monsters not to make noise when their ambush flag is set? I can't find anything about it in progs.
#608 posted by Lardarse [62.31.162.25] on 2011/09/06 04:39:07
Look in the code for an if statement looking at .spawnflags & 3 - there's a comment next to it about zombies having ambush on a different flag.
#609 posted by necros [99.227.131.204] on 2011/09/07 01:23:21
no, monsters still make noise when they have ambush set.
i had to add that specifically into my progs to get silent monster wakeups.
 Then What Does The Ambush Spawn Flag Do?
#610 posted by jt_ [68.42.82.10] on 2011/09/07 04:32:22
Erm, makes them not wake up when they hear something...
#612 posted by metlslime [159.153.4.50] on 2011/09/07 20:49:40
makes them not wake up until they see you -- normally they will also wake up if a nearby monster sees you.
Kind of general programming question about Quake. How does Quake handle broad-phase collision between entities. Does it store them in each BSP leaf and only collide those in the same leaf?
 Linked In
#614 posted by Preach [94.171.245.254] on 2011/10/04 23:28:42
There is a bit of a problem with that approach, which is key to understanding how the engine actually does it. The problem is that an entity might occupy more than one bsp leaf at the same time. So you would actually need a list for each entity of all the leaves that it spans.
Since this might get unwieldy the engine does something a bit simpler, and if you're interested in finding all the code behind it then the thing to search the source for is sv_areanodes*. Areanodes actually just split the space occupied by the world into a fixed depth binary tree by repeated partition along the longest axis of the previous areanode.
That last sentence is concise and accurate, so I instantly fear it's not very approachable. It's like making a new binary space partition which almost entirely ignores the geometry of the world and only uses the minimum and maximum points. It then recursive splits the space into two equally sized parts. It does this by splitting the longest side of the remaining space to try and keep the lengths of all the sides as even as possible.
An areanode is one of the dividing lines between two of these areas, or one of the areas themselves in the case of the leaves on the bottom level of the tree. If an entity straddles a division then it is stored within the list attached to that node. If it straddles many divisions then it is stored in the list belonging to the division furthest up the tree. If the entity is wholly contained in a single area, then unsurprisingly it is stored in the list belonging to that "leaf areanode".
It's then fairly simple to pare down the list of entities to collide against. Find the areanode that your collision trace belongs to (imagine the area swept out by the movement as being a big entity), then you need only test all entities in the subtree with that areanode as the root. If you go through the exact centre of the map then you will certainly be testing against all the entities in the map, but it's not often a problem in practice.
It's worth noting that quake actually has a fixed depth for this tree of just 4. This translates to 16 leaf areanodes representing volumes in the map, along with 15 splits separating them. To illustrate the size of that, if your map is 4 times wider in both x and y than it is tall, which it's easy to imagine something like Castle of the Damned might be, then there would be no areanode splits in the z axis at all, instead creating a 4x4 grid over the map.
Presumably custom engine coders who push both the extents of the bsp format and the number of entities in a map do increase these limits somewhat, either dynamically or just to a higher static cap.
*Warning: If you look too carefully in this region of the source you might find this pair of macros which make the Rune of Black Magic look tame...
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
#define STRUCT_FROM_LINK(l,t,m)
((t *)((byte *)l - (int)&(((t *)0)->m)))
ic... or at least, I think I do :P So this set up is kind of like a grid containing sub-grids kind of set up (can't remember what they're called)?
How does it manage the list of objects as it changes? ie how does it move an object from one node to another?
/slaps self for awful grammar.
 Sorting
#617 posted by Preach [94.171.245.254] on 2011/10/05 02:43:16
The term used within the engine for maintaining these lists is called linking*. You might have heard the term used in QC in discussions about SetOrigin. Typically guides would mention that if you set the origin key directly then the entity will not be correctly linked in the engine. This actually means the entity you moved will still be listed in the collision list for its old position.
In the same way that we have to be responsible and call SetOrigin every time that we move things in QC, the engine code has to call the relinking function every time that it updates the origin of an entity. The nitty-gritty of the relinking is not too complicated, just run through the areanodes until you find one that intersects your entity (or reach a leaf that contains you). Then remove yourself from the old list and append yourself to the new one.
*The term linking does have quite a nice visual metaphor of tying the entities to their areas, but I think it really only arose because the entities are stored in a traditional "linked list" structure.
#618 posted by necros [99.227.131.204] on 2011/10/05 03:44:20
It's worth noting that quake actually has a fixed depth for this tree of just 4. This translates to 16 leaf areanodes representing volumes in the map, along with 15 splits separating them.
this is also the thing that causes large bmodels to flicker or disappear, i believe. especially with rotaters because qbsp errs on the side of (paranoid) caution and makes the bboxes massively oversized. it also doesn't take into account the actual rotations that you will be subjecting the rotater to (this is more understandable though), so if you had like a 1024 long brush that had just a 4x4 cross section, the bbox would still be roughly 1024x1024x1024, even if it only rotated along the long axis.
this makes it get connected to tons of those leafs and and overloads the engine. i guess it just either discards the first links it made, or stops linking when it hits the limit.
 It's Weird...
#619 posted by metlslime [159.153.4.50] on 2011/10/05 04:03:59
you'd think it would simply store the node of the first plane that the bbox is on both sides of. Then when testing two bboxes against each other, find out if their node pointers are related (identical nodes, or ancestor-descendant), then test bboxes directly. Maybe they did that and it wasn't fast enough on the target machines.
One thing to point out -- I attempted making a mapper-oriented console warning in fitzquake that said "entity XYZ touches too many leafs, exceeds MAX_ENT_LEAFS", but what i found was that even tiny id maps had these errors. So even e1m1 breaks the limit on a couple of entities, but you never see a symptom of it unless it goes over so much that none of the 16 leafs are in the current PVS, causing the entity to vanish.
Interesting... time to go off and read some more about data structures :)
What bits of source code should I look up to take a peek at the game loop? Interested in how it sorts through objects and knows what to do with each object :E
 Explorer
#621 posted by Preach [94.171.245.254] on 2011/10/05 10:26:30
I'd say SV_Physics() in sv_phys.c is the main loop to start with. It runs once per frame, looping through all the entities, running physics and QC functions on them. It doesn't give you everything the server does in a frame, stuff like creating the updates to be sent out to the network and parsing the input from the client is elsewhere. But it is the heart of the matter.
One thing that I've found extremely helpful in tackling the quake source code is loading it into a proper IDE like Visual Studio. Being able to right click a function name or typedef and select "go to definition" allows you to focus on figuring out what the functions do, rather than having to switch your train of thought to hunting down the function manually. The history buttons are likewise important so that you can return to the original function just as easily.
Finally "Find All References" allows you to step outwards, for instance to go from Sv_Physics back out to the rest of the server code, and see where it fits in.
 So On The Subject
#622 posted by Preach [94.171.245.254] on 2011/10/12 01:37:21
of looking far too closely at the engine physics source, is this a mistake?
trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
{
trace_t trace;
vec3_t offset;
vec3_t start_l, end_l;
hull_t *hull;
// fill in a default trace
memset (&trace, 0, sizeof(trace_t));
trace.fraction = 1;
trace.allsolid = true;
VectorCopy (end, trace.endpos);
// get the clipping hull
hull = SV_HullForEntity (ent, mins, maxs, offset);
VectorSubtract (start, offset, start_l);
VectorSubtract (end, offset, end_l);
// trace a line through the apropriate clipping hull
SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
// fix trace up by the offset
if (trace.fraction != 1)
VectorAdd (trace.endpos, offset, trace.endpos);
// did we clip the move?
if (trace.fraction < 1 || trace.startsolid )
trace.ent = ent;
return trace;
}
Quoting from fitzquake source but I think it's unaltered. I've bolded the references to offset, because as far as I can see it never gets initialised. It doesn't actually matter in the call to SV_HullForEntity because that function never reads the offset parameter, just uses it as a local variable for internal calculations!
Still, since it's not passed by reference there presumably the same junk sitting there from the uninitialised starting state. Is it just by fortunate placement on the stack that it always gets zero initialised or something? It looks like it should at least mess up trace_endpos if it really contained garbage, or worse the whole SV_RecursiveHullCheck call...
 It's Actually Passed By Reference!
#623 posted by ericw [161.184.107.5] on 2011/10/12 05:04:30
It's only evident when you check the definition of vec3_t in q_stdinc.h:
typedef float vec_t;
typedef vec_t vec3_t[3];
vec3_t is an array type, so it is always passed by reference in a function call. In this case, it looks like SV_HullForEntity always writes to the offset variable, so there's no problem.
That is really confusing, though - at first I though vec3_t was a type that is passed by value, like struct { float x; float y; float z}.
 Ah...
#624 posted by metlslime [159.153.4.50] on 2011/10/12 05:24:09
that's what i suspected too, looking at that code.
 Preach
#625 posted by inertia [68.175.2.88] on 2011/10/12 06:18:32
Do you write about code elsewhere?
 Other Writing
#626 posted by Preach [94.171.245.254] on 2011/10/12 09:57:34
inertia: No, this is basically my one coding outlet! I've got a little article coming up on names in qc which lead me to look up this function and get confused.
ercw: Thanks! Been away from c coding too long I missed that vector thing. And I really should have seen it given the way that the VectorAdd function works, clearly taking a pass by reference in order to mutate the third parameter. Ah well...
 In C++
#627 posted by RickyT33 [94.13.59.170] on 2011/10/13 20:22:16
how does a for loop initialise an integer automatically?
int a;
for (a=1; a<150; a++){cout << a;}
Works, buuuut:
int a; cout << a;
throws a compiler error with
"Run-Time Check Failure #3 - The variable 'a' is being used without being initialized."
Now obviously i could start with:
int a=0;
But what gives the for loop the right to initialise the variable before it begins testing it?
#628 posted by metlslime [159.153.4.50] on 2011/10/13 21:02:56
for (a=1; ...
The a=1 is the part that initializes the variable
#629 posted by RickyT33 [94.13.59.170] on 2011/10/13 22:08:50
Hmmmmm. I kinda suspected that. I guess I'm mis-understanding the for part. I can't help but think of it as an if.
The excercise which has gotten me confused is the following:
int i, j;
bool isprime;
for(i=1; i<100; i++){
isprime = true;
// see if the number is evenly divisible
for(j=2; j<= i/2; j++)
// if it is then it is not prime
if ((i%j) == 0) isprime = false;
if (isprime) cout << i << " is prime. \n";
It's the modulus test part, and my understanding of prime numbers which has gotten me confused.
I inserted this after the second last 'if':
cout << "i=" << i << ", j=" << j << " ";
This way it shows me what the two variables are. I don't understand why the test works.
#630 posted by necros [99.227.131.204] on 2011/10/13 22:48:09
cout << "i=" << i << ", j=" << j << " ";
looks suspiciously like some of the stuff i've been learning about linux and input redirection...
#631 posted by Spirit [80.171.98.14] on 2011/10/13 23:01:58
What exactly don't you understand?
The if (isprime)? If you test a variable without explictly writing eg isprime == 42 it will test if the variable is true (or not false or something like that).
#632 posted by RickyT33 [94.13.59.170] on 2011/10/13 23:16:39
%
% is what i dont understand lol.
Why is 2%3 equal to 2 ?
Why is 45%89 equal to 45 ?
#633 posted by Spirit [80.171.98.14] on 2011/10/13 23:20:01
 Yeah - I Just Read That, Incidentally.
#634 posted by RickyT33 [94.13.59.170] on 2011/10/13 23:36:20
The most useful bit of information I could find on that page was:
^ ISO/IEC 14882:2003 : Programming languages -- C++. 5.6.4: ISO, IEC. 2003. "the binary % operator yields the remainder from the division of the first expression by the second. .... If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined".
The word "nonnegative" scares me a bit TBH.
#635 posted by necros [99.227.131.204] on 2011/10/13 23:36:43
modulus is basically the remainder. like you do long division and stop before going into decimals.
so 2%3 is 2 because 2 can't fit into 3 at all, so you have 2 as the remained.
same with 45%89.
otoh, if you had 3%2, it's 1, because 2 fits into 3 once, and you have 1 left over.
 Necros
#636 posted by SleepwalkR [130.149.148.83] on 2011/10/14 09:44:00
I'm sure you meant to say: 3 can't fit into 2 at all, that's why 2 % 3 = 2. Look at this, Ricky:
0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
etc.
Just try a few examples and you'll get a feel for what the modulo operator does.
 Thanks Necros & SleepwalkR
#637 posted by RickyT33 [217.44.35.184] on 2011/10/14 10:36:27
I also figured he meant a three, but I was pretty cross-eyed already ;)
I think I'm starting to understand it. C++ is weird though, because sometimes you get a negative short. Which is weird. BUT I'm beginning to get my head round it. Which means I'm learning :D
 Sleep
#638 posted by necros [99.227.131.204] on 2011/10/14 22:22:36
haha, apparently math doesn't fit at all into my head. :P
 Ricky
#639 posted by SleepwalkR [85.179.157.100] on 2011/10/15 08:33:22
You're probably messing up the types (using signed short instead of unsigned or something).
 Shoutouts To Awesome Lines Of QC Code #1
#640 posted by Preach [77.98.165.95] on 2011/12/13 16:31:43
A real gem from the walkmonster_start_go code I've never noticed before today:
self.ideal_yaw = self.angles * '0 1 0';
Why not just use self.angles_y? Because that wouldn't be vectorised and involve lots of awesome multiplication!
 Why Not Just Use Self.angles_y?
#641 posted by mh [109.79.197.104] on 2011/12/15 02:33:01
...because then self.ideal_yaw_x and self.ideal_yaw_z may not be set to 0.
#642 posted by necros [99.227.131.204] on 2011/12/15 02:40:51
ideal_yaw is a float though
 Yeah
#643 posted by Preach [77.98.165.95] on 2011/12/15 09:57:08
It's the dot product, so it returns the sum of all three components once you do the componentwise multiplication. Very handy some of the time, but a bit of a waste here.
 Rocket Trails
#644 posted by Mike Woodham [86.174.74.100] on 2011/12/25 09:40:59
What is it that gives rocket (and grenades) their flight trails?
 Model Flags
#645 posted by Preach [86.129.214.167] on 2011/12/25 20:06:18
There are flags you can set on models which select which (if any) effect that applies. If you open one with QMe it gives you a nice tickbox interface if you bring up the model properties box.
 Flags
#646 posted by Mike Woodham [86.174.74.100] on 2011/12/25 20:22:34
Thanks Preach
 Just To Clarify
#647 posted by Preach [86.129.214.167] on 2011/12/25 20:51:30
This is distinct from the QC .flags field - you can't change the particle effects from QC (other than having multiple models and switching between them).
 Flags
#648 posted by Mike Woodham [86.174.74.100] on 2011/12/25 22:23:56
Understood: I found the flag on the model immediately and was able to change them as required.
Is there any effect on performance if I suddenly add lots of these 'particle' effects?
#649 posted by necros [71.99.108.193] on 2011/12/26 02:18:04
i don't think you'll feel it on an engine with the original particles (or even fitz' circular ones) but DP and other engines with 'fancy' particles can start to chug. i know some players using DP found the lava splash effects in ne_ruins would just kill their framerate, for example but i wouldn't even notice it in quakespasm.
#650 posted by Spirit [80.171.98.65] on 2011/12/26 11:35:57
I think older engines have a maximum number of particles they will show.
#651 posted by necros [99.227.131.204] on 2011/12/27 00:13:01
even glquake had -particles though and i always used to use -particles 20000. these days, i use -200000, but i think modern engines don't even use that anymore? i just leave it because it's in a batch file. :P
 Five Particles
#652 posted by Preach [86.129.214.167] on 2011/12/27 00:24:25
A hell knight fires 5 projectiles with trails in a single attack. Launching 1 projectile with five trail should be within scope.
 I Forget...
#653 posted by necros [99.227.132.108] on 2012/01/01 19:14:37
is:
val = random();
val = val + random();
val = val + random();
val = val + random();
the same as:
val = random() + random() + random() + random();
?
 Should Be
#654 posted by ericw [142.179.129.40] on 2012/01/01 21:03:09
as long as assigning the result of random() to val doesn't lose any information.
e.g. for the first case, if the language was C, val was an int variable, and random() returned a float between 0.0 and 1.0, the right hand side of each statement would be truncated to an integer before being stored in val, so in most cases you'd end up with val as 0, unless one of the random()'s returned exactly 1.0. In the second case the floats would be added up before being truncated to an int.
I think in QuakeC they are equivalent because random returns a float and the only numeric type is float.
#655 posted by necros [99.227.132.108] on 2012/01/01 21:08:25
this is purely for quakec.
my question was along the lines of ftos() vs random() and if random() has the same problem ftos does.
my head tells me it shouldn't, since floats are primitives, but my gut tells me qc may do things in a weird way.
#656 posted by ericw [142.179.129.40] on 2012/01/01 21:26:14
Ah. here's the implementation of random: (pr_cmds.c)
static void PF_random (void)
{
float num;
num = (rand() & 0x7fff) / ((float)0x7fff);
G_FLOAT(OFS_RETURN) = num;
}
it looks fine.. I think the "G_FLOAT(OFS_RETURN) = num;" just stores the result in the vm global for return values. so it's not using any shared buffer like ftos.
... but I'm a qc noob so maybe someone more experienced should chime in :-)
#657 posted by necros [99.227.132.108] on 2012/01/01 22:09:49
i'd totally test this, except it's random. XD
 Return Value
#658 posted by Preach [77.98.165.95] on 2012/01/02 00:42:01
Yeah, it's basically about return values in C. A return value of a float is passed by value - i.e. copied to the return value and therefore to the QC. So subsequent calls to rand get different values.
The problem with ftos is that strings in C aren't primitives. Instead what gets returned is a pointer, and passing a pointer by value is effectively passing the string by reference. In the case of ftos there is only a single buffer used, so the pointer which is returned always has the same value: the address for the start of the buffer.
#659 posted by necros [99.227.132.108] on 2012/01/02 00:58:24
in a way, qc is a lot like java...
thanks, preach.
 Interesting Micro-optimisation
#660 posted by Preach [77.98.165.95] on 2012/01/02 11:07:07
The idea that the pointer doesn't change means you can save valuable QC operations by not assigning the return value of subsequent calls to ftos or vtos!
local string a;
a = ftos(self.health); //store pr_string_temp in a
dprint (a);
ftos(self.max_health); //a already stores the pointer to pr_string_temp
dprint(a); //so no need for an assignment
vtos(self.origin);
dprint(a); //vtos uses the same string buffer
Remember: saving 3 QC commands in your debugging routines should be your top priority when coding.
To make it even more efficient, why not just use a global!
string pr_string_temp;
void() worldspawn
{
...
pr_string_temp = ftos(0);
...
}
Never assign to the variable again, and just use the following pattern in all ftos code:
ftos(self.health);
dprint(pr_string_temp);
Although it was born from a daft optimisation idea, there is one nice thing about this coding structure. It makes explicit the gotcha with using ftos - that internally it uses a single temporary buffer. Consequently you'd be much less likely to use it incorrectly by calling ftos twice without writing the buffer to screen or console first.
 Multiple Replies
#661 posted by Pineapple [62.31.161.177] on 2012/01/02 11:29:12
#653:
In theory, yes.
In practice, the original QCC has a bug where only the last of the return values is actually used if they appear in a single statement, so it becomes random()*4. Spike claims to have fixed this in FTEQCC, but I remain slightly skeptical.
#660:
Note that some engines will likely break this behaviour...
#662 posted by necros [99.227.132.108] on 2012/01/02 18:39:18
In practice, the original QCC has a bug where only the last of the return values is actually used if they appear in a single statement, so it becomes random()*4. Spike claims to have fixed this in FTEQCC, but I remain slightly skeptical.
So we're back to it not working then? :(
 Depends
#663 posted by Preach [77.98.165.95] on 2012/01/02 21:21:42
Some compilers will do this wrong thing:
• call random once - store the return value
• call random again - overwrite the return
• call random yet again - overwrite the return
• call random finally - overwrite the return
• add the final return value to itself four time
The difference between this and the ftos problem is that ftos overwrites the result on the engine side, but this bug occurs on the QC side so better compilers can fix it. I'm pretty confident that FTEQCC compiles this correctly but you could test it with the following code:
float counter;
float() increment_counter =
{
counter = counter + 1;
return counter;
}
void() test_compiler =
{
local float total;
total = increment_counter() + increment_counter() + increment_counter() + increment_counter();
dprint( ftos (total));
}
Compilers with the fix should output 1 + 2 + 3 + 4 = 10, the original qcc compiler will output 16. There's no difference here between a builtin returning a float and a compiled QC function which does the same.
#664 posted by necros [99.227.132.108] on 2012/01/02 22:05:16
excellent! everything is peachy, preachy!
 Wow
#665 posted by SleepwalkR [130.149.216.250] on 2012/01/03 10:06:40
you are a poet!
#666 posted by JneeraZ [174.109.109.171] on 2012/02/14 14:52:29
OK, some basic QuakeC questions here...
1. I know if I set the velocity on an entity, it will start moving in that direction. I read that avelocity is a force acting on that. Does that degrade over time or something? Like, is it a temp force or is it always there?
2. Velocity moves an entity regardless of it's angles, correct?
3. Is there a quick and dirty way to tell an entity to face the direction that it's moving in? Like, say I fire a rocket from a point in space -- I want it to face the direction that it's moving in. This is escaping me for whatever reason.
Thanks! :) Hopefully these aren't too rudimentary.
#667 posted by JneeraZ [174.109.109.171] on 2012/02/14 14:54:41
To expand on the rocket things, say the rocket fires from EntityA towards EntityB. So the direction is:
normalize( EntityB.origin - EntityA.origin ); (or vice versa, I can never remember that)
That gives me a unit vector I can use to calc a velocity for flying but how do I make it point at EntityB while it's doing that?
#668 posted by necros [99.227.132.108] on 2012/02/14 20:17:24
1. avelocity is angular velocity and has no bearing on velocity. it does not degrade either. the engine just increments .angles by this much every second.
2. velocity moves an entity IF it's .flags does NOT contain the ON_GROUND flag.
yes, it does move it regardless of angles. to move in the direction of angles, you need to do makevectors(self.angles)
self.velocity = v_forward * someSpeed
3. yes: self.angles = vectoangles(self.velocity) turns the velocity into an angle.
#669 posted by JneeraZ [174.109.109.171] on 2012/02/15 02:25:04
Excellent, thank you! Yes, what you said in #3 fixed my rockets as well. Woot!
 Contentious Quake Design Nitpicking
#670 posted by Preach [77.98.165.95] on 2012/02/18 21:51:04
I contend that the th_* style ai functions are over-engineered in the original qc code.
There is not, to my recollection, a single instance where quake monsters share a th_* function like th_melee, th_pain etc. Therefore it would be best to just have a single function
.float th_handle(float eventnum)
for each monster. The eventnum would then have EVENT_MELEE, EVENT_RUN and so on, and which handler to run would be chosen from a switch statement. There's no reason to suppose that the handling code would all go inline, most likely each statement in the switch would just call the relevant function.
The two big wins of this change would be:
Firstly to get rid of all that cruft for all the other entities in the quake universe.
Secondly to allow many more 'events' to be handled. Whack in default handling which does nothing and you can add event handling for just selected monsters. Things currently dealt with by hacky classname searching like monster waking sounds or attack decision making could be refactored into events.
Having laid out a grand vision, I would grant mercy to the special case of th_pain. Mercy is extended on the grounds that pain functions are parametrised on attacker and damage, and hacking around that would probably be worse than just letting it stay.
#671 posted by necros [99.227.132.108] on 2012/02/18 22:09:25
wouldn't it be better to expand the .functions available to monsters?
for example, replacing all the sight sound checks with wake functions so each monster could have it's own method of playing sounds (some monsters might want different attenuations, other might play random sounds).
one thing i liked about doom3 monsters was that their animations and thinking were separated into two threads. that'd be interesting to do in quake, have your monster model with frame handling and some invisible thinking entity that actually animated based on events and such.
 Hierarchy
#672 posted by Preach [77.98.165.95] on 2012/02/18 23:01:31
Expanding the available functions is exactly the sort of thing that was motivating me. The feeling I have is that there's a tension between adding all the fields a monster could ever need and not burdening all the other entities in the game with stuff they don't use. This leads us to the current compromise where the most vital events get handlers and the rest get hacks.
Adding new fields is possible, but if you wanted to support 50 or 60 events it would get pretty crazy. In a world where lots of monsters shared th_melee or th_stand functions, or even where such things might change dynamically for a given entity (like an injured monster switching to a limping run) the current architecture would have more weight. But as it is, you're born with the think functions of one class, and you die by it, so why not bundle the whole package into one function for the monster to carry about?
#673 posted by necros [99.227.132.108] on 2012/02/18 23:27:32
i know what you mean about the th functions...
i run into it when designing a boss monster that doesn't fit into the standard mold of 1 melee, 1 ranged.
i usually end up overriding the checkattack function for those monsters with a function that directly calls whatever attacks are needed.
still, a function field is stored as, what, an integer? or float? 32 bits is not really a big deal, even with thousands of entities.
seems like it would be more hard to deal with code where there is a single entry point for all monsters and hundreds of checks for each one.
that would be very annoying, i'd think.
 Sketching
#674 posted by Preach [77.98.165.95] on 2012/02/18 23:33:18
You could have a list of the events starting with the mandatory ones
//====MANDATORY====
float EVENT_STAND = 1;
float EVENT_RUN = 2;
float EVENT_MELEE = 3;
...
float EVENT_WAKE
float EVENT_DIE = 8;
//=====OPTIONAL====
float EVENT_OPTIONAL_START = EVENT_DIE + 1;
float EVENT_STRUCK_BY_LIGHTNING = EVENT_OPTIONAL_START;
float EVENT_SHOT_MIDAIR = EVENT_STRUCK_BY_LIGHTNING +1;
...
Then the pattern for event handling goes:
void monster_shamber_handler(float eventnum)
{
if(eventnum < EVENT_OPTIONAL_START)
{
//code to handle events all monsters are expected to deal with
//even if grunt response to EVENT_MELEE is no-op etc.
return;
}
else
{
//handle any other selection of events with set of if..else lines
}
}
In theory you could do some sort of jump table with the mandatory events using the event number as an index. Of course, since qc doesn't really handle integer calculations all that well you'd probably find the most efficient solution was to redefine all the event numbers to already be the desired offset into the table stored as an integer bytewise. Assuming you need 4 qc instructions per handler to call a function and return you'd be looking at
float EVENT_STAND = 0.00000000000000000000000000000000000000000000056051938;
And so on...wasn't there a compiler that let you define integer constants like %4.
 HUD Text Shizzles
#675 posted by Kinn [109.150.216.190] on 2012/02/21 19:35:29
I've never ever looked into mucking around with the HUD before - but would like to do one thing if possible...
You know when you press tab to see your monster and secret counts? Is it possible with QC to change the text "secrets" to say something else? As well as on the end level tally screen?
 Kinn:
#676 posted by metlslime [159.153.4.50] on 2012/02/21 19:44:34
the score bar (when you press "tab") is hard-coded in the engine.
The intermission screen is an image, so you could edit that image to say anything.
 Ah Ok
#677 posted by Kinn [109.150.216.190] on 2012/02/22 00:30:35
hmmm, so i can change one but not the other :/
#678 posted by necros [99.227.132.108] on 2012/02/22 00:40:13
you could always make your own menu/screen.
even with stock quake exe you can make a functional menu that pauses the game.
#679 posted by Kinn [109.150.216.190] on 2012/03/04 00:26:36
you could always make your own menu/screen.
Nah that would be huge overkill for what I'd be doing. Besides, I realised what I originally had in mind is probably just a silly gimmick anyway, I'm gonna shove it to one side for now.
 Brushmodel Texture Swapping
#680 posted by Kinn [109.150.216.190] on 2012/03/06 16:36:20
So let's say I have a brushmodel and i want the texture it wears to change according to events. From what I understand, all I can do is this:
- have an (optionally) animated looping texture with frames following the +0blah, +1blah etc. convention, then change to a non-animated image with the +ablah naming convention, by setting frame = 1 on the bmodel.
What I'd like to do is have 4 different non-animated textures, and i can just swap between any one of these images.
I assume it's not possible without doing crap like having 4 seperate bmodels and hiding 3 of them (or I guess just using 2 if i abuse +0blah and +ablah).
Or is it?
Also I don't wanna use a .mdl
#681 posted by necros [174.113.119.133] on 2012/03/06 19:40:49
yeah, you'd need multiple bmodels.
the frame stuff is hard coded, unfortunately and treats +0 ... +9 as a frame group, hence frame = 0 and 1 only.
 Ok Cheers
#682 posted by Kinn [109.150.216.190] on 2012/03/06 20:06:44
I'll move to plan B which is to do the effect with sprites. Lighting won't be ideal, but i think i can get away with it.
 Lightning Bolts
#683 posted by Kinn [109.150.216.190] on 2012/03/07 17:52:54
so, spawning a lightning bolt:
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteCoord (MSG_BROADCAST, self.enemy_pos_x);
WriteCoord (MSG_BROADCAST, self.enemy_pos_y);
WriteCoord (MSG_BROADCAST, self.enemy_pos_z);
no matter what i set the vector org to, it only spawns the bolt starting from the entity origin - basically the calls for setting the starting point are ignored - is that how quake works?
 Only If The Given Entity Is A Player, Otherwise It Works As Expected
#684 posted by czg [213.112.239.56] on 2012/03/07 18:40:50
 Ah I See
#685 posted by Kinn [109.150.216.190] on 2012/03/07 18:44:17
sneaky, sneeaky quake :}
#686 posted by necros [174.113.119.133] on 2012/03/07 21:10:16
note also that you can only have one lightning bolt per entity.
these days i build my lightning bolts manually out of edicts because every engine besides fq/qs tries to be cute and put in effects. :(
 Stealing Weapons
#687 posted by Mike Woodham [109.156.118.88] on 2012/03/10 15:29:42
What do I need to consider when trying to implement something like this:-
void() steal_weapons_use
{
other = activator;
if (self.spawnflags & SPAWNFLAG_SHOTGUN)
{
other.items = self.items - (self.items & IT_SHOTGUN);
other.ammo_shells = 0;
other.weapon = IT_AXE;
}
};
Or am I running in treacle here?
I can see it taking the weapon and the shells, but it breaks with an error in the weapon_cycle command.
 Activator's Other Self
#688 posted by Preach [77.98.165.95] on 2012/03/10 16:03:07
There seem to be three entities in this story, and I'm having to guess who is who:
self: presumed to be an entity added to the map as a trigger perhaps?
activator: if the above is correct then activator is whoever set off the trigger called self
other: known to be the same entity as activator
The first thing seems to be that other is unnecessary, which makes the function confusing. If we replace other with activator we get:
void() steal_weapons_use
{
if (self.spawnflags & SPAWNFLAG_SHOTGUN)
{
activator.items = self.items - (self.items & IT_SHOTGUN);
activator.ammo_shells = 0;
activator.weapon = IT_AXE;
}
};
We can then see more easily what might be dangerous. We only act if self has the spawnflag for removing shotguns. On that condition, we then set the activator's items to be equal to self's items with item shotgun removed. I'm pretty sure that this line should be referring to activator all the way through.
 Thanks Preach
#689 posted by Mike Woodham [109.156.118.88] on 2012/03/10 16:20:21
I didn't see the wood for the trees.
#690 posted by necros [174.113.119.133] on 2012/03/10 18:36:38
don't know if you trimmed things out for clarity, but you should probably add a quick check:
if (!activator.flags & FL_CLIENT)
return;
just to avoid any possible problems in the case of monsters some how activating it.
 Spawn()
#691 posted by necros [174.113.119.133] on 2012/03/10 19:10:01
is spawn() completely reliable? is there any time where it can fail and not create anything? or it creates an entity but the entity somehow gets lost? maybe if you're spawning many entities in the same think?
 Invalidation
#692 posted by Preach [77.98.165.95] on 2012/03/10 19:24:36
In the standard implementation spawn only fails if there are no free edicts, which produces a game-ending error. As long as it doesn't error out, it returns some entity and as far as I can see there's no way this entity could fail to be a clean slot. But that entity might be more familiar than it seems.
Edict slots aren't allowed to be reused with 0.5 seconds of an entity being removed from a slot*. However, if a reference to an removed entity persisted longer than that it could end up creating a reference invalidly relating to a newly spawned entity. Could a stale reference be somehow responsible for your issue?
*This is not true for the first two seconds of the map, in order to not waste lots of slots if entities are loaded from the map but removed by the qc straight away.
#693 posted by necros [174.113.119.133] on 2012/03/10 19:39:50
right, i totally forgot about that! i still had that .doNotRemove trick from before and i found that the entity is indeed being removed by something else. thanks, i'm off to track that down. :P
 And
#694 posted by necros [174.113.119.133] on 2012/03/10 19:55:18
it's done. thanks! turns out i had some sloppy linked list clean up. i was clearing out the list but forgot to clean up the head link. :P
 Not Qc...
#695 posted by necros [174.113.119.133] on 2012/03/17 06:23:27
this is java, but it's more of a conceptual thing...
finally started working on the inheritance aspect of fgd files for my fgd<>def converter thingy...
essentially, i have multiple lists of objects which represent key/val pairs. these lists can have duplicate entries from base classes that an entity inherits from.
eg: you have 'monster_army' which inherits target/targetname fields from the base 'monster' class.
what i'd need to do is, on demand, collapse the multiple lists into a single one.
ie: when i 'get' a list element, i should iterate through a single apparent list:
monster_army has the fields: (inherits from 'monster')
0: B
1: C
2: D
monster has the fields:
0: E
1: C
2: A
should look like:
0: B
1: C
2: D
3: E
4: A
(duplicate C in 'monster' is ignored because 'monster_army' already had that field)
i can work through the logic of building a new list myself, but the problem is that there are many times where i need to iterate through the (final) list, so every time i .get(i), i'll have to rebuild this list which feels wrong.
is there maybe some more complex data structure that would work better for this? i'm thinking maybe trees due to their non-linear nature?
unfortunately, i've never really learnt data structures more complex than a simple linked list. :S
or maybe there's some absurdly easy solution and i'm just not seeing it.
#696 posted by ericw [23.17.185.198] on 2012/03/17 07:13:59
you should be able to get away without building the final list. I'd store the key/value pairs in a hash table instead of a list of key/value pair objects, and have an object for each "quakec class". then set up a recursive get() function which first checks the object-being-called's key/value pair mapping (e.g. Grunt), and if the requested key wasn't found, call the get() method on the superclass (e.g. Monster) (or return null if there is no superclass - so for a key requested that isn't in either Grunt or Monster).
something like this:
class EntityClass {
EntityClass superclass;
HashMap<String, Object> fields;
Object get(String key){
if (fields.containsKey(key)) {
// the requested key is stored directly in our class
return fields.get(key);
} else {
// the requested key is not in our class, try searching
// our superclass.
if (superclass != null) {
return superclass.get(key);
} else {
return null;
}
}
}
}
hope that helps..
btw here's the javadoc for HashMap.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/HashMap.html
#697 posted by czg [83.253.15.82] on 2012/03/17 08:55:39
If you're only storing the keys and no value with them, I'd recommend using a Set instead of a Map. You should read up on the Java collections framework, as in most cases it already solves a problem for you.
 To Lob Or Not To Lob, That Is The Question
#698 posted by Mike Woodham [86.174.73.229] on 2012/03/17 10:30:47
I have a Lavaman in my map (FMB_BDG) and he does a good job except I notice that there is a point where I can stand and the missiles go over my head. If I move closer, they hit me and if I move further away they hit me up to a point where they drop in front of me.
I can see that MOVETYPE_BOUNCE seems to affect the 'lobiness', and velocity_z seems to affect the height of the lob. What is affecting the gap between the hit range and the no-hit range? I am not too worried about the far distance as the missile falling short is not an issue because I can contain the player, but the over-me-'ead-john lob is not good.
If I change to MOVETYPE_MISSILE and ignore velocity_z I get a straight line missile a la roquette, but this is not good where the player is higher or lower than the Lavaman as dodging becomes too easy.
Are there any good web-sites that explain weapon behaviour (in short sentences with no long words, and mathematics that any four year old can understand)?
 Ericw++
#699 posted by SleepwalkR [85.178.55.133] on 2012/03/17 12:58:34
This is also how I would do it. Note though that the keys will be unordered. If you need them to be sorted in some way, consider a SortedHashMap, e.g. TreeMap.
 Hash Maps
#700 posted by Preach [77.98.165.95] on 2012/03/17 13:43:35
I think everyone is right on Necros' problem that using sets/maps is the way to go, but I think that the implimentations so far have been backwards: So far we've had how to check if a specific element is a member of one or more sets, but what necros is looking for is the ability to list all the unique elements in a collection of sets, omitting duplicates.
The key to doing this is set union. Have a set of properties for the monster, a set of properties for the grunt. When it comes time to output the combined list, use the addAll method to create combined lists which omit duplicates.
 Lobbed Projectiles
#701 posted by Preach [77.98.165.95] on 2012/03/17 14:15:16
The most important mathematical idea for understanding projectiles is being able to imagine the movement in just one direction, to ignore all the other motion.
In particular imagining just how the height changes is important, but it's also the most difficult. It's also quite hard to deal with the idea of projectiles that can go north-south and east-west.
So lets just fix our boss facing north, and think about the horizontal movement of the projectile first. It turns out that the northwards movement of the projectile is exactly the same for MOVETYPE_MISSILE and MOVETYPE_BOUNCE. We fire it with some speed to the north, and it keeps going at a constant speed. Most importantly it takes the same amount of time to come in line with the player.
Now we can think about how the height changes. The MOVETYPE_BOUNCE has exactly the same behaviour as a falling player. Measure the amount of time the MOVETYPE_MISSILE takes to hit the player. If a player could fall from the height the projectile is thrown at down to the height of the target player in that time then the MOVETYPE_BOUNCE will score a hit, otherwise the shot will sail over his head.
So what can we do if it does sail over his head? Well, one trick is to start the projectile with a negative velocity_z, so it is already moving downwards. This will make it fall further during the flight and hopefully hit the player. Alternatively we can reduce the speed it travels north at. This will give a longer flight time and so longer for it to fall. We could combine these two ideas if needed.
Calculating exactly how much adjustment is needed is where you have an unavoidable level of fairly grizzly maths. I'm sure I wrote something about this particular problems but I can't remember if I finished it and ever posted it. You can probably get a good enough function by just measuring the threshold at which projectiles start going overhead, and applying one of the two above fixes when the player is that close(using trial and improvment to get values that work well).
 Thanks Preach
#702 posted by Mike Woodham [86.174.73.229] on 2012/03/17 16:12:46
So, with a zero velocity_z, does the projectile fall from the horizontal at a predetermined and constant rate i.e. no acceleration? And if so, do we (you) know what that rate is?
I'm just thinking that a series of If Thens could adjust the velocity_z and velocity to get to the target in the given time. (Not sure what the player would think of that?)
 Basically
#703 posted by JPL [82.234.167.238] on 2012/03/17 16:13:52
z is a parabolic function, depending of initial velocity, the initial direction/angle and the weight of the projectile, so to say gravity...
x and y can be linear it eases calculation, unless you want to add some wind effects, etc..
Wikipedia gives some mathematics clue for this: http://en.wikipedia.org/wiki/Trajectory
Experiment !
 Gravity
#704 posted by Preach [77.98.165.95] on 2012/03/17 16:51:42
JPL is right that it's not a constant rate, it's an acceleration, and the easiest way to understand it is to experience it in-game. Because gravity affects players in the same way as bouncing missile, you can see exactly how it changes just by falling. In particular if you go on ziggurat vertigo then you can see the change in speed happen in slow motion, which makes it easier to gauge. The next paragraph is optional mathematical detail:
Standard quake gravity is 800 units per second per second. What that means is that after 1 second of falling (from rest) a projectile will be travelling down at a velocity of 800. After 2 seconds that speed has reached 1600 and so on until it reaches the maximum speed the engine allows (which defaults to 2000 units per second I believe). The speed increases smoothly, after 0.5 seconds the projectile has velocity 400 and so on, but this constantly increasing speed means that position changes irregularly.
Despite that, we can use approximations here. The trick is to restrict ourselves to a controlled case. Work out the distance at which the shots are missing the player, and only apply this approximation within that range.
Since we know that the shots we are correcting are close range, we can assume the flight time will be 1 second or less. We can then approximate the falling motion of the projectile as a constant speed of 400 units per second*. Based on that we can do some fairly simple calculations based on the relative height of the player and the projectile's start location. If these differ by more than 400 units then add the difference to the velocity.
The important thing is to get that typical flight time right for the shots we want to correct, detect when we're in that case and then issue appropriate corrections. If my guess at the timescale is wrong please let me know and I'll recrunch the numbers.
*This certainly looks like I just averaged the starting speed of 0 with the final speed (at 1 second) of 800. I will be belligerent and claim I actually performed an integral of the accelerated motion to discover the exact distance a projectile covers in 1 seconds, the answer being 400.
 Experimenting...
#705 posted by Mike Woodham [86.174.73.229] on 2012/03/17 17:48:40
Well, the first thing I did was to manipulate velocity_z, with so-so results. However, by just thinking a little less, and velocitising a bit more, I found a figure for velocity that covers the distance perfectly, whilst still providing an obvious 'lob' effect. The only downside is that if you get too close, you do not really have time to get out of the way.
Still, given that the player starts off x distance from the Lavaman, which IS a dodgeable distance, and given that he does not HAVE to get closer if he does not want to, I may just reduce velocity a bit according to the distance to target, and settle with what I have.
It's not that I don't want to do the maths, it's just that this is just one monster in one scenario for my final Quake map.
Thanks Preach and JPL for the guidance.
#706 posted by necros [174.113.119.133] on 2012/03/17 19:00:10
wow thanks to everyone for pointing me towards those other data structures.
looking around, it seems like LinkedHashSet is the way to go as it is supposed to be only slightly slower than a HashSet (but not as slow as a TreeSet) and preserves the order based on when they were added.
I don't think the Map interface is what i need, since i'm storing more than just a relation between a key.
FGD has many extra bits for key/vals including data type (Target/TargetName/Integer/String/Choice) along with (if a choice) the individual choices as well as a default value (if any), so all that has to be in there, but i'm only interested in the key's name when building the list (as that's how i want to determine if it's a duplicate or not)
anyway, i'll throw some more code at the problem and see what happens!
 Reaction Time
#707 posted by Preach [77.98.165.95] on 2012/03/17 19:20:43
One of the interesting things about projectiles is that for a fixed launch speed there are two angles you can fire them to land at a given range*.
http://en.wikipedia.org/wiki/File:Ideal_projectile_motion_for_different_angles.svg
The above illustrates how that works, but the reason I raise it is because the high lobbed shot, which I think of as the less obvious of the two paths, has a longer flight time. The difference is greatest on the shortest ranges.
This would be a great solution to giving the player enough reaction time. It also would be good at lobbing over any cover between the player and monster, which might make the combat more interesting.
There is however a price to pay, and that price is the need for greater computation. Essentially when you fire on a low trajectory you can land a lot of hits even without getting the range very accurate, because the horizontal line of the attack will usually intersect with the player somewhere. When you go for the tall lob shot your attacking line is much more vertical, and so you need to get the horizontal spot on.
How that would go would be:
• Calculate the vertical range to target h.
• Compute the time to drop to height h:
http://chart.googleapis.com/chart?cht=tx&chl=t=\frac{600%2B\sqrt{600^2%2B2\times800h}}{800}
(here 800 is gravity and 600 is our intended upwards velocity)
• Calculate the horizontal range to our target x
• Divide x by t to get the horizontal velocity v
We now need to make a vector with length v moving towards our target in the horizontal plane:
d = self.origin - self.enemy.origin;
d_z = 0;
d = normalize(d)*v;
Finally we set d_z = 600 and off we go!
*except for maximum range where the two solutions converge on 45°
 Necros
#708 posted by SleepwalkR [85.178.55.133] on 2012/03/17 19:26:18
I seriously doubt that you need to worry about performance in your app. Or am I wrong? Also, if you have more data, you can store an object that represents that data in the hashmap with the name as the key. That's the usual approach anyway.
#709 posted by necros [174.113.119.133] on 2012/03/17 19:31:55
re 707: in doom3, you can see that happen sometimes with hellknights. they usually use the more horizontal trajectory when throwing their fire balls, but occasionally, they'll toss one way up into the air.
re 708: yeah, you're probably right about performance. anyway, managed to get it working in a quick hacked up way. i store keyval lists as arraylists on the entity definitions, but when i call the get method for a keyval index, i build the linkedhashset each time out of all those arrays.
works well for now even though it feels like this is wrong... like i should be storing all the keyval lists as linkedhashsets and using .addall.
 Target Match
#710 posted by JPL [82.234.167.238] on 2012/03/17 20:18:54
I guess the main problem is not to obtain the parabolic curve, that can be even coded very simply like an exponential code (i.e x = x/2 or x = 2x). no I guess the challenge is rather to be able to obtain the projectile to perform direct hit to the player (if not moving). in order to achieve this, a reverse calculation is required: you know player position, monster position, projectile weight, hence it is possible to determine velocity and angle to apply... that could be very interesting as more realistic ;)
#711 posted by necros [174.113.119.133] on 2012/03/17 20:27:21
did this a while ago.. it was supposed to be for a leaping monsters and would trace the parabolic course in increments via a while look and tracelines so check if the leap parabola was clear...
traceFraction = 0;
while(traceProjection <= 1)
{
traceProjection = traceFraction + 0.25; //project the trace. will make for 4 traces.
local vector trace_pos0, trace_pos1;
trace_pos0 = self.origin + ( (dir * (hdist * traceFraction)) + ( '0 0 1' * ( ((vtime * 400)*(vtime * traceFraction)) + (0.5 * (vtime * traceFraction) * (vtime * traceFraction) * -800) )));
trace_pos1 = self.origin + ( (dir * (hdist * traceProjection)) + ( '0 0 1' * ( ((vtime * 400)*(vtime * traceProjection)) + (0.5 * (vtime * traceProjection) * (vtime * traceProjection) * -800) )));
traceline(trace_pos0, trace_pos1, 0, self);
bprint (vtos(trace_endpos));
bprint (" -> ");
if (trace_fraction < 1)
traceProjection = 1000000; //cause a break
traceFraction = traceProjection;
}
dunno if that code is 100% correct... or even helpful. :P
 Necros
#712 posted by JPL [82.234.167.238] on 2012/03/18 08:47:14
I guess what is interesting is not that much the result, but the logical reasoning you made to obtain it ;)
#713 posted by necros [174.113.119.133] on 2012/03/18 17:56:41
oh sorry yeah, should have explained it a bit. :P
you'll notice there's two vars, traceFraction and traceProjection.
these should be only values of 0 to 1.
next is trace_pos0 and trace_pos1.
we determine these points by using that physics formula that describes position relative to time with an initial velocity and taking into account gravity. (i subbed 400 in to any 'g' variables, which, sorry to say preach, i figured out totally by guessing... ^_^;)
this is where traceFraction and traceProjection come in. if you look at the first line of the loop, traceProjection is always 25% ahead of traceFraction.
trace_pos0, then, is the origin of the traceline and trace_pos1 is 25% ahead through the trajectory.
incidentally, you could increase the 'resolution' of the trace by decreasing 0.25 to 0.1 or something to get 10 iterations instead of 4.
if you can imagine a typical parabolic trajectory, what you're doing in that code is tracing a line, first, from the starting point to 25% into that trajectory.
then, from there, tracing another 25% forward to the middle of the trajectory, etc etc.
if at any point the traceline fails (trace_fraction < 1, ie: something blocked the trace)
then we break out of the loop and notify the rest of the code what happened.
basically, i turned quake into a really crappy 3d graphing calculator. :P
#714 posted by necros [174.113.119.133] on 2012/03/18 18:05:00
oops, there was additional information i forgot about (i wrote this years ago so i forgot how it works! :D)
this is the start of the code (before that loop):
epos = self.enemy.origin;
//epos = self.enemy.origin + dir;
zsep = epos_z - self.origin_z;
dist = vlen(epos - self.origin);
dir = epos - self.origin;
dir_z = 0;
dir = normalize(dir);
if (zsep > 64) //player is too high, forget it.
return;
temp1 = epos;
temp1_z = 0;
temp2 = self.origin;
temp2_z = 0;
hdist = vlen(temp2 - temp1);
if (hdist > 768) //player is too far, stop
return;
if (hdist < 440)
{
hspeed = hdist; //do a 1 second jump.
vtime = 1;
}
else
{
hspeed = 440; //max out at 440 horizontal speed and jump higher to compensate.
vtime = hdist / hspeed;
}
i guess the important things is noting that dir is a flattened normalized vector towards the target and that vtime is the amount of time we want to spend in the air.
 Necros
#715 posted by JPL [82.234.167.238] on 2012/03/18 21:06:32
Oh, I see, you made it like a move forward, rotate, move forward, rotate, etc... like polar coordinates or (better) vectorized move: interesting, I was not thinking it was possible doing it this way actually ;)
And thanks for the explanations :)
 PHP Is Kicking My Ass At The Moment
#716 posted by RickyT33 [2.124.172.60] on 2012/03/23 18:08:51
The sooner I can get my assignment finished, the sooner I can get back to mapping :)
This bloody search_array thing is kicking my ass. Trying to use php to search an array of info. Its a multi-dimensional array. I swear I have looked all over for a solution and have had no luck.
http://www.php-forum.com/phpforum/viewtopic.php?f=2&t=17353
 No Php Guru
#717 posted by bear [217.115.56.186] on 2012/03/23 18:26:19
But the search_array func probably isn't built for multi dimensional arrays. Seems to be versions of that in the comments of the search array in the php docs:
http://php.net/manual/en/function.array-search.php
 Yeah I've Been Sifting Through That
#718 posted by RickyT33 [2.124.172.60] on 2012/03/23 19:25:54
I dunno, it seems I'm just not getting something.
I think it's to do with the way I have my array. Which is awkward because It's just the way it comes from the XML file. Blerg.
 Oh God...
#719 posted by jt_ [174.252.232.14] on 2012/03/23 21:13:11
Xml...*shudders*
 Yeah I Know
#720 posted by RickyT33 [2.124.172.60] on 2012/03/24 08:07:10
Any sensible person would design a DB in MySQL, but we are not allowed to use MySQL (go figure?!) - which sucks because any real-world application would use MySQL or SQL or even .net + access or whatever, but 'noooooo', not my retarded course. php + XML is the recipe of the day. Fuck it, I guess I'll learn something at the end of the day ...
 Dude
#721 posted by SleepwalkR [85.178.188.49] on 2012/03/24 08:24:38
ditch array_search and iterate through the arrays manually. It's pretty simple.
 Could You Perhaps Show Me An Example Of A Loop?
#722 posted by RickyT33 [2.124.172.60] on 2012/03/24 08:35:24
I can handle a stupified approach, I just wanna get a fucking A. I don't care if I have to re-design my data structure completely, I have been thinking about this for far to long now and my brain hurts...
#723 posted by Spirit [82.113.119.51] on 2012/03/24 09:41:02
Hey, XML can be fun and it is quite simple if you use a good parser. seriously!
#724 posted by JneeraZ [174.109.109.171] on 2012/03/24 10:53:16
I enjoy the transition from, "Stupid class, can't use a database, have to use XML, *grumble*" to "can you show me an example of a loop?"
Walk before you run, Ricky. :)
 Ricky
#725 posted by SleepwalkR [85.178.188.49] on 2012/03/24 17:25:06
If you don't know what a loop looks like, how can you expect to get an A in a programming class?
Here is an explanation of the most important loop constructs in PHP:
http://nefariousdesigns.co.uk/loopy.html
 Lol - I Do Know What A Control Loop Looks Like
#726 posted by RickyT33 [2.124.172.60] on 2012/03/24 20:33:18
However that is a rather good reference!
Thanks :)
I don't really know that many types of loop, just while loops and for loops.
I think I'm getting somewhere with it now, I used the following bit of code to remove the extra level of array which was preventing me from being able to use the array_search function:
$b=$a['Rrestaurant'];
Dumb, huh? I thought I was going crazy!
Also - I WILL get an 'A'. I could have done the lame thing and just planned a static website. The level of the course is not so high that I have to do a PHP website, but I really want to learn some programming, so I set myself the challenge.
August last year, I had never coded anything really, since messing around with BASIC like 15 years ago.
Now I have coded a text-based version of minesweeper (which is 200KB, fuck)(the second half of the assignment will be probably a discussion of how I can use functions to simplify my code).
And this flippin XML/PHP project. You've got to start somewhere!
But seriously, thanks again.
 Success!
#727 posted by RickyT33 [2.124.172.60] on 2012/03/24 21:51:54
OK, so now that I've figured out how to access my arrays within the array that was within an array, and started iterating through it manually with my loops, I'm having success :)
$search = 'the';
$resultsCounter = 0;
function object2array($object){return@json_decode(@json_encode($object),1);}
$xml = simplexml_load_file("places.xml");
$a = object2array($xml);
$b=$a['Rrestaurant'];
$count = count($b);
for ($x=0;$x<=($count-1);$x++){
$c = $b[$x];
$d = $c['Rinfo'];
if (strpos($d,$search)) { echo $c['Rname'] . '<br /><br />' . $c['Rinfo'] . '<br /><br />' . $c['Rindex'] . '<br /><br />'; $results[$resultsCounter] = $c['Rindex']; $resultsCounter++; }
}
$count = count($results);
for ($x=0;$x<=($count-1);$x++){
echo $results[$x] . ' ';
}
I'm sure that's probably pretty hideous, but its giving me nice search results :) :) :)
 Doh!
#728 posted by RickyT33 [2.124.172.60] on 2012/03/24 21:53:13
$search = 'the';
$resultsCounter = 0;
function object2array($object) {return@json_decode(@json_encode ($object),1);}
$xml = simplexml_load_file ("places.xml");
$a = object2array($xml);
$b=$a['Rrestaurant'];
$count = count($b);
for ($x=0;$x<=($count-1);$x++){
$c = $b[$x];
$d = $c['Rinfo'];
if (strpos($d,$search)) { echo $c['Rname'] . '<br /><br />' . $c['Rinfo'] . '<br /><br />' . $c['Rindex'] . '<br /><br />'; $results[$resultsCounter] = $c['Rindex']; $resultsCounter++; }
}
$count = count($results);
for ($x=0;$x<=($count-1);$x++){
echo $results[$x] . ' ';
}
 Now Try:
#729 posted by bear [217.115.56.186] on 2012/03/24 23:57:30
some better variable names and have a look at foreach
 Yeah
#730 posted by SleepwalkR [85.178.120.41] on 2012/03/25 00:04:51
Don't call variables 'a' or 'b' - give them a name that reflects their meaning in the program.
 Ah - Good Idea.
#731 posted by RickyT33 [2.124.172.60] on 2012/03/25 00:21:37
$wholeArray
$wholeCumbrianRD
$wholeRrestaurant
$wholeKey
 Craving Your Indulgences Again
#732 posted by Mike Woodham [86.174.73.229] on 2012/03/25 16:32:25
I don't do much qc but whenever I do I find myself running into brick (BRICKL_0 or similar) walls.
I have a procedure that I want to run x times as selected from the editor (self.something = x). I want to say along the lines of:-
void () Proc1
do some stuff
while (self.something >0)
do this
wait random y to z seconds
self.something = selfsomething - 1
ewhile
do some other stuff
endproc
(I know I am mixing languages, I am just trying make it look obvious what I am doing)
When looking at 'think' and 'nextthink' examples, they all seem to act on an external procedure/function before returning to the calling procedure/function. I also see use of recursion i.e. a procedure/function calling itself.
Is it necessary to use 'think' and 'nextthink' for timing purposes in my ditty above or is there some other construct available. If I need to use 'think' and 'nextthink' is it therefore advisable to separate the 'while/ewhile' (or whatever loop is used) into its own proc/func?
#733 posted by necros [174.113.119.133] on 2012/03/25 16:43:40
you are thinking about it the wrong way.
best to think about what gets done in a frame and what doesn't.
nextthink and think is what you need to delay over multiple frames.
doing a while loop will do everything in the same frame.
in this case, you don't want a while loop at all.
void() proc1
{
//some stuff here
self.think = proc1; //run this again
self.nextthink = time + (some random amount here);
}
the way nextthink works sort of is that the engine looks at what nextthinks are > current time and when they become < current time, the engine sets nextthink the 0 and runs the .think function with self as the 'thinking' entity.
 Necros
#734 posted by Mike Woodham [86.174.73.229] on 2012/03/25 16:58:26
So the engine is not waiting for my procedure but it will have my 'thinks' queued up? Also, do I not think of this a true recursion?
By the way, I just ovelayed the draflam2.spr with the bigexp.spr (just via an entity choice in the editor and using two entities) and it looks pretty smart. I am not sure what it will look like to a player seeing it for the first time in a game - you know how fussy Quake people are :) But it looks good enough to blow the head of a Vermis!
#735 posted by necros [174.113.119.133] on 2012/03/25 17:12:48
no, it is not recursion.
recursion is when a function calls itself.
you can accomplish this in qc with the usual method:
void() proc1
{
//stuff
proc1();
}
this also does everything on the same frame, just like for and while loops.
when you use thinks, it is the engine that is calling the function when nextthink ticks by.
for the explosion, if you're feeling adventurous, you could try throwing a bunch of MOVETYPE_TOSS invisible entities out of the explosion point that spawn explosion sprites themselves. ;)
looking forward to seeing it.
 Queuing
#736 posted by Preach [77.98.165.95] on 2012/03/25 19:39:36
To add, there is no queue with think functions, you only get one. So if you have code like
self.nextthink = time + 0.5;
self.think = CleanTheDishes;
self.nextthink = time + 2;
self.think = CookDinner;
the second think function overwrites the first one and so you end up eating off dirty plates. One way to fix that is to move the code which sets up CookDinner into the CleanTheDishes function, chaining the functions one after another.
This worked because our two functions were dependent. If you need your entity to think about two independent things one solution is
to have a master think function. This should think regularly, and check timers on your entity manually. The way that playerprethink and playerpostthink handle powerups running out is an example of this pattern.
If that's too complicated, the other way is to have two separate entities, as each one has its own think function and nextthink timer.
 Preach
#737 posted by Mike Woodham [86.174.73.229] on 2012/03/25 22:07:25
Nice analogy; because we don't want to be eating off dirty plates now, do we?
It is falling into place, so thanks.
 QCC
#738 posted by sock [24.82.147.76] on 2012/04/04 16:52:51
I have been compiling my own progs.dat file using the tools from the ID FTP. Is there a good base of .QC files? Has the community got an agreed on base? Any recommendations? Something to start from?
 All Can Be Found Here:
#739 posted by rj [86.29.94.69] on 2012/04/04 19:11:37
 Door Key Use Sound Troubadour Verily
#740 posted by Kinn [86.176.167.133] on 2012/04/04 19:41:45
Ok, this is fairly what-the-christ.
So, I'm running around my mod opening doors with keys. Use a key, door opens - it just plays the door open sound. I'm thinking hang on...didn't it used to play a "use key" sound before when it opened?
I then check vanilla quake. But no, even playing vanilla quake - no mods - key doors are only making the door open sound when they open.
I look in the QC - vanilla QC - the door is *trying* to make a "use key" sound, but it's immediately getting overridden by the "door open" sound (same channel). Looks like that's how it behaves all the time. So, another id bug to fix then. But why do I have a very clear memory of hearing the use key sound in vanilla Quake??
And more creepily, why did Scampie hear it on some compiles of his map, but not on others??
What is this door devilry??
#741 posted by necros [174.113.119.133] on 2012/04/04 20:37:56
sock: and definitely use a new compiler.
you can use more c conventions like for loops and increment and decrement operations.
also removes arguably useless stuff like needing semicolons after function braces.
kinn: not sure, but maybe because czg's progs from his last map pack had a fixed variation where the key sound plays and the door opens after a short delay?
 More Door Bollox
#742 posted by Kinn [86.176.167.133] on 2012/04/04 20:38:09
ok, so i've fixed the key use sound thing, and also for visual effect added a small delay between the key being used and the door actually opening. This introduced me to something that I never knew anything about before. Namely this:
in door_touch, if I replace the call to door_use(), with:
self.nextthink = time + 1;
self.think = door_use;
The door actually opens after about 10 seconds, not 1 second. (whu?)
if I write:
self.nextthink = self.ltime + 1;
self.think = door_use;
The door opens after 1 second, as expected.
do doors play by totally different rules when it comes to time and nextthink shizzle?
 Hah
#743 posted by Kinn [86.176.167.133] on 2012/04/04 20:40:05
wrote that before seeing necros' post :}, didn't know czg did this but maybe that's where i'm remembering it from...
#744 posted by necros [174.113.119.133] on 2012/04/04 20:42:59
preach made a fantastic post about this explaining how nextthinks work on MOVETYPE_PUSH entities:
http://celephais.net/board/view_thread.php?id=60097&start=330&end=330
 Append /\
#745 posted by necros [174.113.119.133] on 2012/04/04 20:45:43
also of note, setting .velocity on a MOVETYPE_PUSH entity without setting a .nextthink will do nothing.
.nextthink must be set higher than .ltime in order for the engine to update position based on .velocity
 Compilers
#746 posted by sock [24.82.147.76] on 2012/04/04 21:32:26
@rj, thanks, I am still learning where everything is hiding! :P
@necros, I got the qcc compiler from ID and it would not work under 64win so I got hold of FTEQCC instead. The original ID files produced a ton of warnings and crap messages. I don't suppose any of that has been cleaned up and a new qc pack of files is anywhere? Or should I not worry and just add my own stuff to the pile?
Are there any QC libraries? Luckily czg released his source so I can see how he did the trigger spawn routines. Is there other things that everyone uses?
 Necros/preach
#747 posted by Kinn [86.176.167.133] on 2012/04/04 21:33:41
thanks, that was useful. Preach - never stop quakeing, you are an asset.
So, from what I gather, because time was not advancing from the door's point of view, when I set self.nextthink = time + 1; it still had a self.ltime of like 0.1 or something, so the "ten second" delay i mentioned earlier was basically due to however long the game had been running up until that point + 1 second. lol.
Funny that I'm still learning new things about quake, but then again I've never dicked around with push ents before, which is why i've never come across this :}
 Sock It
#748 posted by Preach [77.98.165.95] on 2012/04/04 22:17:44
Sock: http://www.btinternet.com/~chapterhonour/clean%20source.zip ought to be handy.
It's my cleaned out copy of the qc source, only for the purpose of defeating all those warnings. I might have made some other minor tweaks but I'm pretty sure it's faithful to the basic game. The only real compromise I added to it is a pointless, vestigial function at the bottom of DummyFunction which defeats the warnings about .wad and .light_lev not being used in the progs, even though you must define the fields.
 Broken Link
#749 posted by sock [24.82.147.76] on 2012/04/04 23:12:09
@Preach, that is awesome what you have done, but I can't get the link to work?
 Arrgh
#750 posted by Preach [77.98.165.95] on 2012/04/04 23:55:24
Forgot to test the link, turned out the ftp failed because the server dislikes filenames containing spaces. Renamed to
http://www.btinternet.com/~chapterhonour/cleansource.zip
 Awesome
#751 posted by sock [24.82.147.76] on 2012/04/05 00:09:00
Thanks Preach that has saved me a ton of effort trying to work out what is my mistake and what is broken already.
 Not Sure If This Has Been Covered Before...
#752 posted by necros [174.113.119.133] on 2012/04/06 05:08:59
if i have two entities, one with .nextthink = time + 0.01 and another with .nextthink = time + 0.02 will the order the thinks occur be based on nextthink or just the order the entities are stored in the list in the engine?
my gut tells me it's the latter, and that makes me sad. :(
#753 posted by necros [174.113.119.133] on 2012/04/06 05:10:48
didn't say, but it should be obvious, i'm assuming the next frame will be longer than 0.02 seconds after. say 0.1 seconds after to be clear.
time = 0
->a.nextthink = time + 0.01;
->b.nextthink = time + 0.02;
time = 0.1
a fires first, guaranteed? or it might be a or b based on it's position in the list.
i should think before i post. -_-
 You Are Correct
#754 posted by Preach [77.98.165.95] on 2012/04/06 10:47:13
If the frame takes longer than 0.02 then it is strictly in the order that the entities appear in the entity list.
Interesting fact though, say that instead we start at time 17
a.nextthink = 17.01
b.nextthink = 17.02
Now at 10fps the next frame starts runs at server time 17.1. However, during the think function for "a" time will be set to 17.01, and during the think function for "b" time will be set to 17.02. This change literally applies only to the QC variable, not to anything else in the server.
Back to the original problem, a lot of the time with the think intervals that you have chosen players today will see a think before b because the cap on fps is 72, which is high enough for a frame between 0.01 and 0.02. Beware of the effect in the previous paragraph though, if you are setting the nextthink values from within individual think functions for "a" and "b" it may not be the case that
a) b.nextthink - a.nextthink = 0.01 (even accounting for floating point error!)
OR
b) that b.nextthink won't occur in the next frame!
That second one needs a bit more explanation and in particular would benefit from concrete figures. We will say that the server issues a frame every 0.014 seconds.
Frame i:
server time = 17
b.nextthink = 17.003
Frame ii:
server time = 17.014
b's think at 17.003 executes and contains the qc:
b.nextthink = time + 0.02;
Since the engine sets time = 17.003 during the think, we now have
b.nextthink = 17.023
Frame iii:
server time = 17.028
So b executes a think in consecutive frames!
If you really need execution in order you might have to concoct a "priority queue" style system, with a new fakenextthink field. That would mean a linked list of entities so that the following pattern holds:
self.fakenextthink <= self.nextent.fakenextthink
You insert into the queue by traversing the list until your fakenextthink is <= the next fakenextthink. Finally you'd need a function that runs from startframe and traverses the queue, running fakethink on all the entities which are due. Since the queue is in order of fakenextthink, they run in the desired order and as soon as you reach one which is not yet due to run, you know you can stop traversing.
Two tips: firstly don't forget to purge the entities from the queue before you fire their events! It's very likely that entities will want to reinsert themselves into the queue from their own fakethink calls, so you need to be aware of that. Secondly, I'd keep up the practice of setting time = fakethinktime for the duration of the fakethink call (then you MUST reset it to evaluate the next entity on the queue).
These two tips combine for an interesting effect: you can have multiple fakethinks occur in a single frame, since they get reinserted into the queue with a fakenextthink that might still be lower than the server time. I suppose to be sure of correctness we need to make sure the loop of execution is less traversing the linked list, so much as always looking at the head of the list and popping it if execution time has arrived.
I have another use for this priority queue in mind which is less technically involved and more generally applicable, so I might go away and write it up with some nice complete code over the weekend...until then!
#755 posted by necros [174.113.119.133] on 2012/04/06 18:30:14
thanks for confirming that for me. i was looking at the engine source, and that was what it looked like, but i'm not familiar with it enough to be sure.
i do remember the bit about time being set to nextthink time on think calls. i've used your 'servertime' workaround often because of it. :)
as for making a fakethink sorted list, i thought of it, but i only have one bit of code where it would be important, and it felt like it was better to just solve the problem by working around it rather than making the whole fakethink system.
thanks!
 Sounds
#756 posted by Mike Woodham [86.174.73.229] on 2012/04/06 19:33:51
Is it possible for one entity to affect (stop) the sound of another entity e.g by forcing a null.wav to play on that other entity's channel?
I have just noticed on an old map of mine that when the player dies the music keeps playing, which seems wrong to me. I thought I might just be able to drop a 'sound' line into Player DeathSound to say kill the music, then carry on and play whichever death sound you want. But I do not know how to use the sound(self,...) parameter to point to a specific entity.
Alternatively, could I stop all sounds just before playing the Player DeathSound?
 Mike:
#757 posted by metlslime [159.153.4.50] on 2012/04/06 19:48:19
instead of "self" in that sound call, use the name of another entity.
#758 posted by metlslime [159.153.4.50] on 2012/04/06 19:48:42
(i.e. the entity that you want to silence)
#759 posted by necros [174.113.119.133] on 2012/04/06 20:10:50
also of note: make sure you play that sound with 0 attenuation to make sure it is 'heard'.
if you are outside audible range, the engine won't even bother registering the sound and so won't interrupt a previous one playing on that channel.
 Sounds, Part The Second
#760 posted by Mike Woodham [86.174.73.229] on 2012/04/06 21:13:10
metlslime: thanks, once I realised that I needed to add the entity name to ALL parameters, we wuz cookin' on gas.
necros: it's in the form of:
sound (self, CHAN_VOICE, self.noise9, self.volume, self.distance);
where 'noise9' happens to be the null.wav, and everything else is already set from within the original entity's entity definitions.
It works just fine now: music stops, player does his death sound and dies gracefully, monks start chanting a dirge - I keep allowing myself to be killed because I find it ever so slightly amusing :)
(One day, I'll get the hang of this .qc stuff)
#761 posted by necros [174.113.119.133] on 2012/04/07 05:07:34
concerning c++
i've been messing with that fake GI hack with MH/Aguirre's light and the main block right now is integer precision...
specifically, in order to get better results, i need to add more suns. the more suns i add, the brighter everything gets.
i'd need to use a light level of maybe 0.5 or less.
unfortunately, everything's in ints.
how hard would it be to convert everything to floats and would that markedly slow down light calculations?
is it even worth doing? :P
 Heh...
#762 posted by necros [174.113.119.133] on 2012/04/07 05:08:46
so... i posted that and then i just thought of a better solution (albeit, one that's way more hacky).
i was thinking i could assign all sunlight a different light style and then give it a light style of z to n instead of m...
#763 posted by necros [174.113.119.133] on 2012/04/07 05:49:28
yeah, that didn't work that well. :P
 Holy Lmaps Batman!
#764 posted by Kinn [86.128.113.123] on 2012/04/07 14:11:21
Out of interest - what are the performance implications of using styled lights on that sort of scale?
 Basically None
#765 posted by Preach [86.136.150.139] on 2012/04/07 14:42:30
All lights in quake are styled, you can see the code which sets the styles in the worldspawn function with. Performance costs are only incurred when the style changes, either due to an animated style (multiple letters) or calls to lightstyle to alter the style.
Incidently there's a trick to making easy lightning effects relating to this. Lighting tools put all the sky lighting on style 0, but we can see that it's possible to alter the levels of style 0 in the same way as other styles. If you put all of your static, sourced lights on a different style, you can reserve style 0 exclusively for light from the sky. Then you can quickly switch the style to intensity "z" to create a flash of lightning while keeping indoor lighting constant.
 Well Damn
#766 posted by Kinn [86.180.65.35] on 2012/04/07 14:57:37
I know what I'm gonna be doing now!
Cheers.
#767 posted by necros [174.113.119.133] on 2012/04/07 18:46:36
Incidently there's a trick to making easy lightning effects relating to this./q>
that works ok, but tends to look a little boring because the shadows don't change. it's also annoying because you have to remember to set all your normal lights to a style other than 0. although, i guess you could code up your qc to default to another style.
i'm currently trying to haxor in mutliple 'lightning' suns so i can get fake varying lightning strike positions. i'd leave the lightning suns 'off' and then flicker them on when needed. note that you could only have max 3 of these because 4 is the max number of styles allowed. :(
sadly, i know nothing about c++, my only experience being with java which does pointers automatically and seems, overall, a lot simpler, so progress is slow for now.
#768 posted by necros [174.113.119.133] on 2012/04/07 18:46:42
awwww
#769 posted by metlslime [67.188.81.46] on 2012/04/07 20:59:21
it's also annoying because you have to remember to set all your normal lights to a style other than 0. although, i guess you could code up your qc to default to another style.
I don't think qc will help you; styles have to be set up in the map file (either "style" or "targetname" on each light entity) so that light.exe knows about them.
#770 posted by necros [174.113.119.133] on 2012/04/07 21:14:32
oh that's right. ouch.
 Control
#771 posted by Preach [86.136.150.139] on 2012/04/08 00:41:35
I'd edit your fgd/def file to make other lights default to a different style. I'll admit I've not tried it, so maybe the effect isn't all that dramatic. It sounds like it's one of those things where you could get a good effect in the bsp format, but that maybe the tools for it aren't quite there yet...
 Touchy Triggers
#772 posted by necros [99.227.156.158] on 2012/04/20 22:42:52
is there some kind of bug where triggers touching each other can cause a touch function to run on the other trigger?
ex: trigger A and trigger B are touching.
player touched trigger A, trigger A and trigger B both run touch functions.
#773 posted by negke [31.18.185.232] on 2012/04/20 22:59:08
Sounds like you forgot to set the trigger_dont_link flag.
#774 posted by necros [99.227.156.158] on 2012/04/20 23:08:30
you're thinking about door_dont_link.
this happens with just normal triggers.
 Joke; Didn't Work
#775 posted by negke [31.18.185.232] on 2012/04/20 23:14:12
 Shape
#776 posted by Preach [77.98.165.95] on 2012/04/20 23:14:59
Any chance that it can be because the trigger brushes are oddly shaped, and the resulting bbox shaped triggers end up coinciding? Never heard of an effect like this before, might have to take a look at the map to figure it out.
Another tool that I've only recently begun to use is the pair of builtins traceon and traceoff. Calling the former means that all the QCasm instructions get printed to the console until you call the latter. It's about as close as you can get to a debugger for QC, and a lot of the time it's much quicker than adding a bunch of dprint statements to nail down a bug. Putting them round the touch functions might be helpful.
#777 posted by necros [99.227.156.158] on 2012/04/20 23:22:01
this actually happened in ne_ruins.
it's in that little corridor between the two maps, in the start map, there are a couple of triggers that get fired depending on flags (ie: just entered the map or returning).
except they were both firing until i spaced them 1 unit apart.
i'll have to try out those builtins...
 Re Traceon/off
#778 posted by necros [99.227.156.158] on 2012/04/21 00:25:46
yikes... that's a LOT of output.
it'll take some time to get used to reading this.
i suspect it'll be best to turn it on and off sparingly.
 Deluge
#779 posted by Preach [77.98.165.95] on 2012/04/21 00:30:29
Yeah, it's not something that you want on functions running many times a second,it might be necessary to turn it on right after the basic touch rejection code. The thing I found it best for was when I have a function with lots of if branches, and needed to work out which ones it was taking or rejecting.
 Unsolicited Advice
#780 posted by Preach [77.98.165.95] on 2012/04/22 15:47:03
Suppose that you are writing a mod which other mappers will use, and you want mappers to be able to control a parameter. In this post I will use corpse-duration in a corpse removal system as an example. Traditionally if you wanted a global property then you would add a field to worldspawn to set it.
Apart from it being a bit of a waste to add a field to every entity which is only ever read from worldspawn, I think there is a better pattern, which is a bit more powerful. The key use-case is a property which a mapper might want to vary as well as set initially. Corpse lifetime arguably fits this criteria, for example: during a large horde combat you might want to remove corpses faster than the rest of the map.
My suggestion is to create a new entity function as follows:
float corpse_duration;
void() set_corpse_duration =
{
corpse_duration = self.count;
if(!self.targetname)
remove(self);
}
Then the way to set the corpse_duration initially is adding a point entity with classname set_corpse_duration and count equal to the desired duration.
Can any of you keen entity hackers see how we change it dynamically? Well, we set up an entity with the desired count, but with "classname" "info_notnull" and "use" "set_corpse_duration". If we set a targetname then every time we trigger this entity it sets the corpse duration. If you want to codify it as less of a hack you could invent a new classname for this kind of entity like set_dynamic_property, but it doesn't need any supporting code.
The remove(self) bit of code is a bit ugly, but it makes sure that initially setting the property doesn't cost you an entity, yet the info_notnulls can be used multiple times.
 Mismatched Flags
#781 posted by sock [24.82.147.76] on 2012/04/23 01:59:24
I am trying to query a monster to see if the current enemy has an artifact enabled. I am using (self.enemy) and I checked to see if it a player. I query the flags (self.enemy.flags) and it does not show the player flags properly. I tested this by using an artifact routine (void() powerup_touch) to print to the console what it was doing and it produced a different flags value.
I double checked the classname field and other player variables and it is certainly looking at the same entity, except the monster query will not show the content of the flags correctly.
Is there something strange about queries with the player flags?
#782 posted by necros [99.227.156.158] on 2012/04/23 03:02:29
what value are you seeing? how are you querying for flags? flags must be checked via bitwise operation (self.enemy.flags & FL_CLIENT) will return 1 (true) for the player.
are you saying you do the above operation and it returns false when the monster is angry at the player?
also note that players gain and loose flags a lot during play, godmode, notarget, onground, partialground...
 Fixed
#783 posted by sock [24.82.147.76] on 2012/04/23 05:35:19
I was mixing up .item and .flag queries. I was too tired to see the difference and could not understand why. doh!
 Ideas/tutorials For Useful Entities...
#784 posted by wakey [178.191.195.208] on 2012/04/25 00:26:40
to add to progs.dat.
I'm quite the noob when it comes to coding.
Included misc_model entity from a old tutorial, but that was just copy/paste and compile.
For example i would love to have such swinging door's/ pushable func_rotate things like in ne_ruins.
Googled, found no tutorial for that yet, and dont know what other stuff could come handy.
Suggestions?
 Inside3D Is The Place For Everything QC
#785 posted by negke [31.18.185.232] on 2012/04/25 10:48:57
They have a forum and a set of tutorials on the site.
necros code is a different matter. I think it's part QC and part evil arcane magic, or something.
 QC Beginnings
#786 posted by Kinn [86.164.173.251] on 2012/04/25 12:39:37
For example i would love to have such swinging door's/ pushable func_rotate things like in ne_ruins.
If this is your first foray into QC I would forget all that stuff and just start small. Most of the QC tutorials you can find online are the "make a grunt shoot rockets"-type stuff but they will help you learn the basics.
The sort of stuff necros does (pseudo-physics movers and whatnot) is not going to be achieved with copy and paste.
#787 posted by necros [99.227.156.158] on 2012/04/25 19:01:18
this is from last year, but i haven't really done much to the pushable rotaters since then anyway.
http://necros.slipgateconstruct.com/temp/ne_rotation_pushableRotaters(17.12.11).qc
i doubt it will work by plugging in, and it should be obvious it requires the hipnotic rotation code, but you can at last see what's going on. it also needs a lot of work still-- there is no implementation for other axis of rotation because those must factor in gravity.
overall, the concept is pretty simple: the movewalls have a touch function now that takes the speed that the player touches them with and dumps it into the rotators which then decays that speed over time. there's more to it of course, like translating velocity into angular momentum and such, but i'm not going to explain the whole thing. i think i've posted about it before, but i forget where.
for coding qc:
knowing about unit vectors, dot product, normalizing vectors, reflection, etc... (but you can always google this stuff up and learn it on the spot if you are not averse to that)
if you know some physics, that can help too, but you don't need to be a rocket scientist. (wow, when will that saying get old? maybe it already has...)
 Thx Necros & Negke
#788 posted by wakey [80.121.104.224] on 2012/04/25 20:36:21
for the code & link.
Looks very complicated for me, but the concept sounds logical, hopefuly i will learn enough about qc to understand the code eventualy.
Let's see what i will find on inside3d :D
#789 posted by necros [99.227.156.158] on 2012/05/04 01:56:14
um.. what is trace_plane_dist?
the name implies it's the distance to the plane it hit, but after testing, i was seeing very strange values being returned, some in the thousands from a short 80 unit trace.
#790 posted by necros [99.227.156.158] on 2012/05/04 05:48:51
a bit more testing... seems to be the distance from the origin based on the axis of the plane, so a trace on a face on the y/z plane returns distance from origin along the x axis.
non-axial planes returns strange values, some kind of combination of the different axis based on the slope of the plane?
 It Is Probably The Plane Distance Using The Plane Normal
#791 posted by czg [212.16.188.76] on 2012/05/04 08:36:56
http://mathworld.wolfram.com/HessianNormalForm.html
You can define a plane in 3D space using its normal vector and distance from origin (in the direction of the normal)
#792 posted by necros [99.227.156.158] on 2012/05/04 18:59:43
thanks for clearing that up. :)
#793 posted by necros [99.227.156.158] on 2012/05/11 20:01:03
is there any way to 'reset' frame aliases back to 0?
or is making a new qc file the only way?
 Compiler Extensions
#794 posted by Preach [77.98.165.95] on 2012/05/11 21:04:56
QTEQCC supports resetting the frame aliases using
$framevalue 0
(literally, the keyword is framevalue)
The need to make an extension suggests it can't be done normally.
#795 posted by necros [99.227.156.158] on 2012/05/11 21:27:57
you mean fteqcc?
anyway, thanks. :)
 Centerprints
#796 posted by necros [99.227.156.158] on 2012/07/16 19:49:42
What is the maximum centerprint length?
Does it matter if you use the extra centerprint that allows multiple arguments?
Fitzquake has a bug that allows longer centerprint strings, but Quakespasm 'fixed' this, so that strings that display fine in Fitzquake spam the console with errors and truncate the string in Quakespasm.
:(
 Centerprint Article
#797 posted by sock [24.84.102.77] on 2012/07/16 20:15:39
http://www.inside3d.com/qip/q1/qcenhanc.htm#centerprint
From the page :
* The maximum number of characters in one string or multiple strings printed at once is around 2000.
* The maximum number of characters per screen line is 40, independent from the current resolution.
* The maximum number of lines per screen is 13, as more will cause weird problems in 320x200.
The links says max 2000 chars but 13 lines of 40 characters is 520 total. I assume Quakespasm is not liking those above limits?
#798 posted by necros [99.227.156.158] on 2012/07/16 20:22:00
I brought this up before, and iirc, the 'limit' was actually higher than it should be. Apparently, the centerprint had some kind of unchecked thing which allowed strings that were too long to go through and it was only through luck that data wasn't being corrupted somehow. (and probably why it was never noticed?).
 Bizarre Problem...
#799 posted by necros [99.227.156.158] on 2012/07/25 01:05:08
I've got a bmodel with MOVETYPE_PUSH and SOLID_TRIGGER that moves via velocity.
Normally, I can be inside this entity when it moves.
For some reason, if I touch a rotate_object (which has no touch function, is MOVETYPE_NONE and is SOLID_NOT), the moving trigger bmodel becomes blocked! (it runs it's .blocked function too).
It's the weirdest thing ever...
 Reproduction
#800 posted by Preach [77.98.165.95] on 2012/07/25 01:39:30
This sounds like it might be quite a specific problem and so hard to reproduce, can you e-mail me a map/progs that displays the behaviour?
 Solution
#801 posted by Preach [77.98.165.95] on 2012/07/26 02:04:42
This might be a little opaque for anyone outside of me and necros.
The engine code underlying this problem is quake's blocking detection system. It's crude to the point of being technically incorrect, but infrequently enough that nobody has cared - before now. When a door moves, each entity is tested against the door:
Is the entity within the bbox for the door?(i.e between its mins and maxs, not exact intersection) If not move on.
Is the entity currently stuck? If not move on.
At this point the code attempts to move the entity the same distance as the door moved, in the hope this pushes it clear.
To see if it worked, we test again if the entity is stuck.
If it is stuck, we declare the door blocked and revert all the movement for this frame.
The flaw in this system is that we only test if the entity is stuck, not if it is stuck in the door. You can test this with a map with a func door which encloses the player without touching them in any way, combined with a solid brush which impales the player inside. The door will crush you without ever making contact.
Here endeth the general lesson. Specifically for necros: Your post missed something important out, the func_pressureBolt is MOVETYPE_FLY, which apparently causes the player to count as stuck and hence block the trigger. You set MOVETYPE_NOCLIP at line 73, but change to MOVETYPE_FLY at line 95. If you delete line 95 your trigger will work again.
If you are worried this class of bug might recur in other circumstances, I can outline an alternate design which uses a static rather than moving trigger, just ask!
#802 posted by necros [99.227.156.158] on 2012/07/26 03:02:23
If you hadn't found the solution, I would have done the trigger movement via setorigin (since there's no collisions to check (beyond .touch of course).
You set MOVETYPE_NOCLIP at line 73, but change to MOVETYPE_FLY at line 95
*sigh* man, one day I need to rewrite my code... that's just sad. :P
But yeah, you are a genius man. I never would have imagined the rotation controller entity was behind the problem. Both it and the accompanying rotate_objects are SOLID_NOT. Why would the engine even check collision if it's not solid? Maybe because movetype_fly was intended for use with projectiles?
Very strange!
Thanks for yet another awesome bit of quake wisdom. :)
 Motionless
#803 posted by Preach [77.98.165.95] on 2012/07/26 21:43:20
My suggestion was going to be have a trigger which starts off at full height. Then just add
if(other.mins_z < self.owner.maxs_z)
return;
to the touch function for that trigger. Here self.owner is the visible moving entity which marks the upper end of the trigger. If there was no visible part you could calculate the height mathematically based on the time since triggering.
I'm still not sure why MOVETYPE_FLY matters, it might also be tied up in using a bsp model for the func_pressureBolt...the physics code is pretty dense and circuitous.
#804 posted by necros [99.227.156.158] on 2012/07/26 21:51:51
Is this also related to that bug where a lift moving up/down will get the player 'stuck'? I had it happen more on some lifts than others, for example, that big lift in ne_ruins with the rotaters did it so much, there is actually code that sets the blocking entity's origin 1 unit up to stop the player being crushed.
 Necros
#805 posted by Baker [69.47.162.203] on 2012/07/27 08:40:09
Can that physics issue happen in DirectQ or the RMQ Engine? Both those engines have very intricate physics fixes that essentially make sure that the physics always run at Quake normal speed.
I ask because it is an engine physics issue, that isn't something you should worry about too much because MH has the cure that needs to get into other engines.
 Sheesh Missing Word ...
#806 posted by Baker [69.47.162.203] on 2012/07/27 08:42:34
"I ask because IF it is an engine physics issue" ... [basically can you reproduce the problem in the RMQ engine or DirectQ with that lift? If not, maybe mentally mark that problem off the proverbial list ...]
#807 posted by necros [99.227.156.158] on 2012/07/27 08:44:13
you can test to see if it's happening by going loading ne_ruins, turning on dev mode to 1 and riding the lift up.
It's very random and may or may not happen, but you will see "corrected bmodel collision bug." if the qc detects a block that shouldn't happen.
it doesn't happen in DP, so if the collision fixes are as extensive as it is in DP, then it probably doesn't. The collision in DP is really sweet.
#808 posted by Baker [69.47.162.203] on 2012/07/27 11:03:14
That's enough info then. Yeah, DarkPlaces is fixed up in that way as well (and has been for ages and ages).
I wouldn't spend any time worrying about this one.
I intend to extract the fixes from RMQ/DirectQ and more or less document how to implement them.
[I just haven't done it yet because of the things on my list, well, it's kinda boring and tedious ... ]
 Bsp Format Question
#809 posted by Preach [77.98.165.95] on 2012/07/29 12:49:32
I'd like to check something with people who are familiar with the BSP file format. Suppose we have a very simple map with one room containing a func_wall. The room has 20 faces and the func_wall has 6. Is it correct that there is just one list of 26 faces in the bsp:
0
...
19
20
...
25
then the model headers go
"world: I own 20 faces starting at face 0"
"wall: I own 6 faces starting at face 20"
The same then goes for vertices, nodes etc, that the bsp file collects all alike data types into a single list and each model in the file operates on a subset of that same list? (with exceptions like textures which are instead shared).
Why? I was thinking about the external bsp models trick - initially I was just trying to write a tool to pack them back into a single bsp for release. However, if the above is correct, it might also mean that the external file gets a new lease of life - as a limited way to help maps which exceed bsp limits
#810 posted by necros [99.227.156.158] on 2012/08/03 02:42:52
interesting...
rezTarget.think =
rezTarget.nextthink = time + 0.1;
compiles fine with fteqcc, but flat out crashes quake. :P
 Is It Correct That There Is Just One List Of 26 Faces
#811 posted by mh [78.152.240.205] on 2012/08/04 17:59:59
Yes, that's the way everything is stored, but there are subtleties.
"Faces" as you understand them in a map have little relationship to surfaces in the generated BSP file. QBSP will remove faces (facing out, never visible, overlapped, etc) and generate more from splits, so you can't really use the map file as any kind of guideline to what the BSP will contain.
Regarding use of external BSP models, you can use them to go through BSP limits, but lighting will be wrong for them. Lighting for an external BSP model doesn't take account of any geometry in the world that might occlude those lights, and they fail to get dynamic lights. That might be OK with you, but it might not be OK with someone playing your map.
 It's My Lighting Aand I'll Cry If I Want
#812 posted by Preach [77.98.165.95] on 2012/08/04 18:28:33
That's good to know.
On lighting: Although losing dynamic lights is a shame, I don't think that the static lighting is much of a obstacle.
Although I've been talking external bsps in general, the best use-case for external models is for objects that rotate or move. Static lighting of course can't get these right, so there's less worry they might be lit "wrong". Along the axis of rotation it makes more sense for the lighting to be uniform, instead of baking in a shadow which will be wrong as soon as the object moves.
For statics moved outside the BSP for limit reasons only, I suppose it's not impossible to write a version of light that applies occlusion from a base map onto an external bsp (using the code-path from the light executable which occludes lights on models 1-n based on the geometry from model 0, except loading model 0 from a different file to model 1). Think I'll stick to the bsp packer for now though...
#813 posted by mh [78.152.240.205] on 2012/08/04 19:27:50
Dynamic lights can be fixed in-engine; there's a (slight) performance cost but the visual consistency is more than worth it. I have it in my current (unreleased) codebase, but I don't believe any other engine has implemented it yet (aside from those with fully real-time solutions).
Along the axis of rotation it makes more sense for the lighting to be uniform, instead of baking in a shadow which will be wrong as soon as the object moves
Definitely agree with that.
I suppose it's not impossible to write a version of light that applies occlusion from a base map onto an external bsp
It's an interesting idea. It would break if more than one entity used the same BSP model (an example would be a generic door modelled as a BSP) but for limited special cases it should work.
#814 posted by necros [99.227.156.158] on 2012/08/04 20:15:52
would it be possible to make an 'fake ambient occlusion' mode in light.exe such that, when enabling it, it creates an array of suns like it does with sunlight2, except that these suns do not require sky textured brushes?
that way we could make some external brushwork and get some nice shadows that look good from all rotation angles.
heh, maybe I should do that... I'll see if I can puzzle it out.
#815 posted by necros [99.227.156.158] on 2012/08/04 21:58:09
http://necros.slipgateconstruct.com/temp/sillygi.jpg
hmm, seems like it was easier than I thought it would be. o.0
 If Anyone's Interested:
#816 posted by necros [99.227.156.158] on 2012/08/04 22:36:20
http://necros.slipgateconstruct.com/downloads/ne_ag_LightMHColourR2.zip
This is based off of mh's coloured light/multicore tweak of aguirre's light utility, so it has all the good stuff.
Two new command switches are added:
-fakeGISun2
Makes sunlight2 cast additive light in a full sphere (as opposed to a dome).
-fakeGIMode
Makes sunlight2 not require skybrushes (ie: the light comes from the void)
NOTE: REQUIRES -fakeGISun2
Also note you need to set the worldspawn keys 'sunlight' to '1' otherwise it's not activated at all and the 'sunlight2' settings should be low, 2 or 3. 4 is pretty bright.
I basically just turn off the check that requires sunlight to pass through a skybrush first, so with -fakeGIMode, the sunlight comes from the void.
Source included. Some small changes to LoadEntities() and TestSky() and maybe one or two other tiny things I've forgotten.
 Good Stuff
#817 posted by Preach [77.98.165.95] on 2012/08/04 22:50:09
The spherical illumination might also be handy for coagula style maps.
#818 posted by necros [99.227.156.158] on 2012/08/05 03:11:40
not bad results on space maps with only the fake gi light enabled: http://necros.slipgateconstruct.com/temp/nesp10GI.jpg
Might be cool to do another space map one day with this lighting. The only thing is that exposed faces tend to look flat. The above screenshot is only interesting because of those high walls.
#819 posted by mh [109.79.236.164] on 2012/08/05 04:13:36
That actually looks pretty cool; kinda radiosity-like.
#820 posted by necros [99.227.156.158] on 2012/08/05 20:43:04
Dunno if anyone has mentioned this before (Preach maybe?) but I've been using a lot of multi-entity setups these days and cleaning up after them has become rather annoying so I used this trick to simplify things:
void(entity e) remove_builtin = #15;
.void() removeFunction;
void(entity e) remove =
{
local void() _removeFunction;
entity tempSelf;
if (e.removeFunction)
{
_removeFunction = e.removeFunction;
e.removeFunction = SUB_Null;
tempSelf = self;
self = e;
_removeFunction();
self = tempSelf;
}
remove_builtin(e);
};
Create a wrapper for the remove builtin that first checks if a .removeFunction is set, and if so, run it.
Then, I just create a unique function for each multi-entity that takes care of any child entities.
Note how we first save a reference to the .removeFunction() before clearing it. This is to prevent some recursive removeFunction running where (if you are not careful) you remove a child entity that then removes the parent, that then removes the child... etc...
This makes sure it only runs once.
ps, sorry about formatting.
 Destructive
#821 posted by Preach [77.98.165.95] on 2012/08/05 23:18:25
Works like a destructor in C++ (*), I like the recursion guard you put in there, I don't remember seeing that before.
Another place where this can be helpful is if you have some kind of linked-list structure, where removing an entity would break the chain. You can set a removeFunction which repairs the list before and after the entity which is getting removed.
* How long can it be before we get a QC++ compiler bringing the full power of object orientation and inheritance to our favourite game?
 Loading MDL Files
#822 posted by necros [99.227.156.158] on 2012/08/07 06:28:21
Trying to load .mdl files with java following this: http://tfc.duke.free.fr/coding/mdl-specs-en.html
For the most part, I got the data in fine, but for some reason, there seems to be a few extra bytes AFTER the frames that I don't know what to do with.
The number of bytes isn't consistent either, sometimes it's 10 bytes, other times it's 9 or 8.
Obviously, this screws up the next frame from loading properly because all the bytes are offset by however many were left over.
I tried just doing the dumb thing and skipping over these extra bytes after loading a frame, but the number of extra bytes can change within the same model.
Is this a real thing (extra bytes between frames) or am I just messing something up?
#823 posted by mh [78.152.239.241] on 2012/08/07 07:44:36
Extra bytes between frames isn't normal. Possible that your struct sizes are being padded out to some alignment? I don't know Java so I'm not certain if it even does that, but it's the only off-the-top-o-me-head explanation I can think of.
#824 posted by necros [99.227.156.158] on 2012/08/07 07:59:19
Thanks, I was just looking for confirmation that there are no extra bytes. :)
Java doesn't have structs or any of that, so I'm just reading everything in byte and byte and converting things to big endian ints and such.
I'm sure I'm just reading something in wrong or I missed something.
 Gotchas
#825 posted by Preach [77.98.165.95] on 2012/08/07 12:19:36
One of the things to watch out for is where there are mdl_vertex_t being loaded to define the bounding boxes of the frames and the like. Make sure you're reading the vertex normal in all of those places, even though it's not used.
#826 posted by necros [99.227.156.158] on 2012/08/07 20:42:16
For the first frame, the data seems to be fine up to (at least that I can easily check) the frame name.
I parse each byte as a char until I get to the first byte that is 0, then I start loading vertex objects.
The problem seems to be somewhere during the vertex loading.
I'm using a 5 frame model with 5 verts.
Looking at the file itself, I see 48 bytes between one frame name and the next, so it looks like each frame is 48 bytes long. (the frame data actually starts 12 bytes before the name, there's one int (4 bytes) and 2 mdl_vertex_t (2 * 4bytes))
The mdl_vertex_t struct has an array of 3 unsigned chars and then a single uchar, so that means each vertex should be 4 bytes long.
So with 5 verts, that should mean that all the vertex info should be 5 * 4 = 20 bytes.
Take those 12 bytes mentioned above and we have 32 bytes. The name is "POLY1" so that should be 6 bytes for the name (including \0).
So in total that's 38 bytes and then 10 bytes left over.
#827 posted by necros [99.227.156.158] on 2012/08/07 20:47:00
hm.. ok, seems like typing it out helped me see the problem...
Looks like the String for the frame name is ALWAYS 16 bytes, not until the next 0 value. It loads in some junk characters but that explains the 10 byte offset (16 - 6).
That's really bizarre.
#828 posted by necros [99.227.156.158] on 2012/08/07 20:58:41
actually, I guess it sort of makes sense.
c just stops reading strings when it reaches the first \0, but I guess they didn't want to bother with a dynamically allocated char array so those junk bytes are actually whatever was on the guy's memory when he saved the file...
 Yup
#829 posted by Preach [77.98.165.95] on 2012/08/07 21:12:49
You have permission to zero all of that out nicely when you export though! Also, don't forget to test your code with grouped frames and grouped skins before you're through - it always seems to be going so well until that point...
#830 posted by necros [99.227.156.158] on 2012/08/07 22:19:38
I wasn't really going to bother with that for now.
Mostly, I just wanted to redo that "qcStarter" program I made so you could load a model and generate some basic monster code complete with a spawn function.
But now I'm thinking it'd be pretty cool to make a modern mdl editing program.
#831 posted by mh [89.19.71.35] on 2012/08/08 01:00:04
c just stops reading strings when it reaches the first \0, but I guess they didn't want to bother with a dynamically allocated char array so those junk bytes are actually whatever was on the guy's memory when he saved the file...
Yup, that's it. The struct in the C code is defined as follows:
typedef struct {
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
char name[16]; // frame name from grabbing
} daliasframe_t;
Reason why is when loading an MDL you can just load the entire file into a single buffer, then walk through the data setting and incrementing pointers as needed. If every daliasframe_t is the same size the job becomes much easier.
Same basic principle applies to other model data that contains a string name; e.g. textures have a fixed 16 char array for their names.
#832 posted by necros [99.227.156.158] on 2012/08/08 01:24:32
Makes sense, they would design the format to make it easy on themselves, not some guy digging into it 15 years later. :P
Now to see if I can draw it to screen!
I think understanding exactly what the heck is going on with the so called 'compressed coordinates' is going to be the really hard part. o.0
 Hahaha
#833 posted by necros [99.227.156.158] on 2012/08/08 01:37:30
 This Is Interesting
#834 posted by RickyT33 [94.13.59.186] on 2012/08/08 01:40:40
I always wondered what the algorithm was for drawing point to point in 3D.
Also I'm stunned that I am following this. It actually makes sense to me(!) now that I can program a little.
#835 posted by mh [89.19.71.35] on 2012/08/08 01:58:44
they would design the format to make it easy on themselves
...and they even failed at that!!! http://www.team5150.com/~andrew/carmack/johnc_plan_1997.html#d19970707 (section beginning "anatomy of a mis-feature").
well, it was supposed to be a fiend...
It's real close though, and a whole ton better than my first attempt at doing this with C# 8 or so years back.
#836 posted by necros [99.227.156.158] on 2012/08/08 02:19:08
http://necros.slipgateconstruct.com/temp/nowthatsafiend.jpg
Silly mistake... tried reading in verts on the frames directly. :P
 Oh Thanks For That Link
#837 posted by necros [99.227.156.158] on 2012/08/08 02:20:12
It's nice that that .plan stuff is archived. I never had internet back then (plus I was too young) but that seems very interesting now. :)
#838 posted by mh [89.19.71.35] on 2012/08/08 02:36:41
Good stuff with the fiend. You gonna take this all the way and do texturing too?
The .plan archive is essential reading, it's a great window into the thinking behind why much of Quake is the way it is, and can be very informative for decisions of the "should I add/remove/change this feature?" kind.
 Skinzz
#839 posted by necros [99.227.156.158] on 2012/08/08 08:03:07
 Good Job, Necros...
#840 posted by generic [67.235.210.16] on 2012/08/08 13:24:43
I can see its eye in that shot :)
 Heresy!
#841 posted by jt_ [174.252.254.224] on 2012/08/08 14:13:18
Fiends don't have eyes.
 Yes They Do!
#842 posted by negke [31.18.178.240] on 2012/08/08 18:29:46
You guys don't do a whole lot of looking at things, do you?
http://www.lunaran.com/pics/fiends...
And now, shambler will argue that those aren't actually eyes:
 Herp Derp
#843 posted by Shambler [31.18.178.240] on 2012/08/08 18:32:40
#844 posted by Spirit [80.171.143.135] on 2012/08/08 18:41:26
I thought those were nipples?
 Coding-related Questions
#845 posted by Tronyn [24.79.202.92] on 2012/08/09 00:15:04
Now that the RMQ project has split up, what's happening with the BSP2 format? Will it still be updated? Do any engines other than the RMQ Engine support it yet?
Also, is anyone willing to do some coding for new boss monsters? PM is currently cleaning up and debugging Drake, but doesn't want to spend time adding entirely new monsters/features/etc. I totally understand this POV but it'd be nice if Drake had a unique final boss of some sort.
Looks like eyes to me. Now the Shambler, on the other hand...
 Can Someone Make Me A Demon Skin
#846 posted by Drew [199.180.99.21] on 2012/08/09 03:16:37
With no eyes? This is horrible.
 Hm
#847 posted by madfox [94.215.208.34] on 2012/08/09 08:54:41
Glases are fine, horns another question.
http://members.home.nl/gimli/gdemon.jpg
#848 posted by necros [99.227.156.158] on 2012/08/09 09:57:54
maybe I'm just tired, but that was hilarious. :D
 @Tronyn
#849 posted by gb [46.142.19.93] on 2012/08/09 12:35:33
Since I was linked here from IRC, I might as well answer to Tronyn:
FTE and Darkplaces (and Hmap2) support BSP2, but DP's version is slightly different.
I would guess that DirectQ also supports it, and Baker and Rook's engines might as well.
I have switched to Warsow's FBSP for my project, so BSP2 will get no updates from me. The Schism team would probably be the ones to maintain it now. Perhaps ask at their forum.
You should talk to MH, Spike and Lordhavoc to get the BSP2 support in those engines harmonised.
Quakespasm did not want to support BSP2 when I asked.
I don't normally read this forum anymore, but I'm willing to help where I can. Poke me per mail or IRC if someone wants to talk to me.
 OBJs + PCX!
#850 posted by necros [99.227.156.158] on 2012/08/10 01:11:24
http://necros.slipgateconstruct.com/temp/objdrawing.jpg
Thanks to preach for his pcx loading code in the md3tomdl converter. The runlength encoding stuff was confusing the crap out of me.
Also, I had to flip the pcx data on the x axis AND reverse the pixel array order after loading it... is that normal? If it's not then I must have messed up the UVs on the OBJ...
 Heh
#851 posted by necros [99.227.156.158] on 2012/08/10 01:18:40
actually, flipping x axis and reversing the order is basically just flipping y axis right? :P
 Triple Post
#852 posted by necros [99.227.156.158] on 2012/08/10 01:38:41
looks like it's a thing with obj... just flipped v component when loading the obj instead of goofing with the pcx.
 Y Axis
#853 posted by Preach [77.98.165.95] on 2012/08/10 10:15:43
There is an issue to be aware of with "intuitive" coordinates and storage of data. The natural order of storing skin/image data (at least the one taken in the mdl format) comes about I think from their usual representation as a string (in the purest array of numbers sense). Since we are used to text flowing from left-to-right then step down a line and repeat (for english-speakers) we extend that idea to the order pixels should be stored in the skin.
The place where this begins to cause a conflict is when we start thinking about cartesian co-ordinates on the skin. The standard mathematical axes on a graph has the y value increase as you move upwards. So if you have something that wants to put the origin of the coordinates in the bottom-left of the skin, you need to reflect the skin in y to compensate.
Having said that, if you're actually going to render the 2d skin somewhere, you really ought to apply the reflection to the skin vertices rather than the image file itself. Otherwise you will cause a lot of confusion for the user who has an expectation on what their skin looked like.
#854 posted by necros [99.227.156.158] on 2012/08/10 19:40:18
Having said that, if you're actually going to render the 2d skin somewhere, you really ought to apply the reflection to the skin vertices rather than the image file itself. Otherwise you will cause a lot of confusion for the user who has an expectation on what their skin looked like.
Yes, this is what I ended up doing. I want to be able to display the skin either for drawing on (probably not) or changing UV coordinates, so having the thing upside down is not an option.
Turns out that this is a common thing with the OBJ format as many of the loading examples I read had a bit of code involving flipping the v component of the texture coordinates.
 Woohoo
#855 posted by necros [99.227.156.158] on 2012/08/11 06:27:00
OBJ -> MDL perfectly functional! FUCK YEAH.
Still can't import more than 1 frame, but I don't think that's going to be a big deal.
 Coding Challenge
#856 posted by Preach [77.98.165.95] on 2012/08/11 12:39:05
Suppose that we have the following functions:
is_first_player: returns true if self is the first player in the server
is_last_player: returns true if self is the last player in the server
toggle_func_playerclips: finds all func_playerclip entities in the map and toggles them between SOLID_BSP and SOLID_NOT.
Your task: comment and critique the following scheme for implementing func_playerclip entities:
1) add
if(is_first_player())
toggle_func_playerclips();
to PlayerPreThink.
2) add
if(is_last_player())
toggle_func_playerclips();
to PlayerPostThink.
The main question for consideration: is there any way for a player to become 'stuck'? Extra credit for considering the implications if is_first_player and is_last_player are not available.
 Coding Challenge Fixed
#857 posted by Preach [77.98.165.95] on 2012/08/11 12:40:22
Forgot to preview so the entities weren't encoded...
Your task: comment and critique the following scheme for implementing func_playerclip entities:
1) add
if(is_first_player())
toggle_func_playerclips();
to PlayerPreThink.
2) add
if(is_last_player())
toggle_func_playerclips();
to PlayerPostThink.
#858 posted by necros [99.227.156.158] on 2012/08/11 21:35:38
You might not be able to change .solid like that without setting model.
Might be safer to do the func_togglewall trick where you translate the clipmodel far away when 'off' and put it back into place when 'on'.
Beyond that, at first glance, seems like it would work?
 Re: Gb
#859 posted by Tronyn [24.79.202.92] on 2012/08/11 23:51:12
Hey, thanks for the response - helpful stuff. What's your email / how can I contact you? PS all the stuff on your blog looks amazing. Cheers.
 Clipped Out
#860 posted by Preach [77.98.165.95] on 2012/08/12 04:01:49
You might not be able to change .solid like that without setting model.
Might be safer to do the func_togglewall trick where you translate the clipmodel far away when 'off' and put it back into place when 'on'.
Yeah, I explained myself badly. The plan was to only describe abstract functions, so you could assume they were correct without getting bogged down. I leaked too many implementation details...
There's still one case I can think of where it breaks down though - the trick is to work out when the player moves other than within the player physics code. There's also a more philosophical quandary with pointcontents I meant to bring up in the first post.
I'm glad you mentioned togglewalls, because although they seem quite hackish with the far-away trick, it has some hidden advantages. The prime one is avoiding ever toggling solid status within a touch function - which can be a fatal error. Building a monsterclip with the same broad outline would now become feasible.
You do have to bind the toggling to calls to walkmove and movetogoal, because monsters don't have the simple physics-wrapping functions that players do. This means that the monsterclip is imperfect in a way that the playerclip is not: falling or jumping monsters will pass through monsterclip. Still, better than a kick in the teeth.
#861 posted by necros [99.227.156.158] on 2012/08/12 04:09:27
You do have to bind the toggling to calls to walkmove and movetogoal, because monsters don't have the simple physics-wrapping functions that players do.
This is what I do right now. To avoid toggling every monster clip, I bind specific clips to specific monsters via a target->targetname style link, that way if a monster has no monsterclips associated with it, it doesn't toggle anything otherwise, it's only toggling a single monsterclip.
I suppose you could just make one giant monster clip entity for the entire map, but I'm not sure if that's bad having an entity with collision cover such a huge area so I've left it as localized clips.
#862 posted by necros [99.227.156.158] on 2012/08/12 04:50:08
I think I got a little side-tracked...
There's still one case I can think of where it breaks down though - the trick is to work out when the player moves other than within the player physics code. There's also a more philosophical quandary with pointcontents I meant to bring up in the first post.
Why would it move outside of engine physics? Feeding .velocity in still has to wait for the engine to process it.
Unless you mean setorigin()? But I think it's safe to assume using setorigin is always going to break collision.
Hm.. well, unless you are doing some funny trickery where you are using a proxy to move the player...
#863 posted by Preach [77.98.165.95] on 2012/08/12 11:51:22
But I think it's safe to assume using setorigin is always going to break collision.
Yeah, agreed.
Why would it move outside of engine physics?
Still inside engine physics, but outside of the player's physics pass.
#864 posted by necros [99.227.156.158] on 2012/08/12 19:02:36
hm... Maybe when you're standing on a bmodel that's moving? ie: train or lift
#865 posted by Preach [77.98.165.95] on 2012/08/12 19:23:06
Maybe when you're standing on a bmodel that's moving? ie: train or lift
Bingo. Probably not a big deal once you know about it, because usually those things are put in for the benefit of the player and you're unlikely to intentionally clip off their route, just something that users of the entity would have to be aware of.
#866 posted by necros [99.227.156.158] on 2012/08/12 19:27:05
The whole player movement on other bmodels thing is kind of fuzzy for me. It's not true movement because the minute you jump, you loose the bmodel's velocity and just get your own personal velocity back.
It's too bad because it stops things like throwing the player off a fast moving object or launching them through the air from a catapult.
 Jumping Monsters
#867 posted by sock [24.84.102.77] on 2012/08/19 23:01:04
I want to calculate the height and speed to make a monster jump a certain distance. I know the origin of both the start and finish points but I don't know how to calculate the speed and velocity in QC.
I know there is 'trigger_monsterjump' but you have to specify or just guess the right amounts until it is right. is there a way I can do a quick QC formula to get rid of the guess work?
 Pretty Easy
#868 posted by Preach [77.98.165.95] on 2012/08/19 23:45:09
Start by picking a velocity upwards, call that v_z. Let d_z be the height of the end point minus the height of the start point.
Once your monster launches, the only thing affecting it is gravity, which accelerates at 800 units per second per second(*). We will appeal to one of the standard equations of motion (with constant acceleration)
s = ut + ˝at˛
Where s is the distance travelled, u is the initial velocity, t is time and a is the acceleration. Substituting the values from above and rearranging:
400 t˛ - v_z * t + d_z = 0
with solution t = (v_z + sqrt(v_z˛ - 1600 d_z) )/800
On level ground this simplifies to:
t = v_z / 400
Now that we have the time t it takes to fall to the correct height, we need only divide the horizontal distance between the start and end points by t to get the required horizontal velocity. Sum the horizontal and vertical velocity vectors and you are done.
We seem to have complete freedom on how to choose v_z, but there are two things to think about. Firstly flight time is roughly proportional to v_z, so vary it according to how long you'd like the jump to last. Secondly in the case that d_z is positive (the end point is above the start point), there is a minimum requirement to v_z. The value inside the square root must be positive for the equation to work, so take care.
Please also remember that although we have solved the equations exactly, the simulation of the motion in the engine will not be exact, and in any case rounding errors will occur. Do not rely on any method to give you 100% accuracy - the landing point may even vary a small amount depending on framerate.
The really interesting case is the one where you have a fixed total velocity and still want to try and land on a particular point, but no space for that right now.
(*) 800 is the default, but in reality you should use the value of sv_gravity. It should be easy to replace the constant, but the explanation focuses on the important variables for clarity.
#869 posted by Spirit [82.113.106.93] on 2012/08/19 23:47:54
check if some mods with "z-aware ogres" (one of the worst quake gameplay changes people like to call a bugfix) are open-source and allow copying, maybe you can use the calculation from their aim.
 Confused
#870 posted by sock [24.84.102.77] on 2012/08/20 00:56:41
Thanks Preach for the explanation but I still don't understand what to code in QC. I know values for some stuff but not the initial velocity. Also I don't mind this is not 100% accurate, I just want something that is roughly right to the nearest 64 units.
I know the following values:
start and finish origin
(s) distance = finish_z - start_z
(a) acceleration = 800 (will use sv variable)
(t) time = s / 200 (wild guess)
(I assume objects travel 200 units forward top speed, it would be nice to know what this value is for monsters)
Things I don't know:
(u) initial velocity = ??
formula:
s = ut + ˝at˛
Expanded out:
s = u * t + sqr ( ( a * 0.5) * t )
I don't know what 'u' is, how do I re-arrange this to find initial velocity (u)?
@spirit, z aware monsters are not all bad, the problem is players don't expect the change and get angry because things are different for no apparent reason. The best solution for z aware monsters is to link them to a high skill level and make them visually different.
 Arbitration
#871 posted by Preach [77.98.165.95] on 2012/08/20 01:27:06
u is defined in the first paragraph:
Start by picking a velocity upwards, call that v_z.
The terminology is a bit mixed up, u is the standard name for the initial velocity in that equation; the name v_z was chosen earlier to suggest a vector component style but in retrospect confuses things.
The key is that it's arbitrary, you have complete freedom to pick whatever upwards velocity you like, then you calculate a forwards velocity to match it. I say complete freedom, but there is some guidance in the paragraph 4th from the bottom.
#872 posted by necros [99.227.156.158] on 2012/08/20 01:48:48
It helps to break things down a bit to understand the problem.
So first is a very basic part of the whole problem, the horizontal speed.
If velocity is 600 units/sec, then that means, in 1 second, you have a distance covered of 600 units.
Seems dumb, but the next part is what you are trying to figure out:
If you KNOW the horizontal speed you want to move at, then what you need to do is find out how high to jump so that you stay in the air for that amount of time.
At this point, it can be easier to wing it.
First find the horizontal distance:
(self is some monster)
vector vec = self.origin - self.enemy.origin;
vector vec_z = 0; //this flatten the vector
float hdist = vlen(temp2 - temp1);
next we decide how fast we want the guy to jump:
float hspeed = 600; //fiends jump this fast horizontally
at this point, we could do something like this:
float vtime = hdist / hspeed;
vtime is now distance / speed (which is units of time)
So we have the amount of time needed to stay in the air.
vector dir = normalize(vec);
self.velocity = (vtime * 400) * '0 0 1' + (dir * hspeed);
the vtime * 400 part is the winging it bit. It works well for most values below super fast velocities.
#873 posted by necros [99.227.156.158] on 2012/08/20 01:50:30
also, it might be a good idea to cap some values. depending on how far the monster is from it's target, vtime can potentially be quite long, meaning the velocity needed to stay in the air will be silly high.
either that or disallow the jump completely beyond a range.
#874 posted by necros [99.227.156.158] on 2012/08/20 01:51:34
ohhh, finally, this is only accurate for cases where both monster and target are on equal height. for any other case, you will need to use the physics equation.
 The Final Jump
#875 posted by sock [24.84.102.77] on 2012/08/20 04:49:22
Thanks for the help everyone, here is my final chunk of code for my jump system. It works really well and all the jumps I have setup always go downwards so the gravity/4 looks more natural than using /2.
some constants I used:
MONAI_JUMPSPEED = 200;
DEF_GRAVITY = 800;
Code:
local vector jumporg, jumptarg, jumpdir;
local float jumpdist, jumptime;
// Calculate jump velocity towards destination node
jumporg = self.origin;
jumptarg = self.target_ainode.origin;
jumporg_z = jumptarg_z = 0; // Flatten vectors
// turn towards jump destination node
self.ideal_yaw = vectoyaw(jumptarg - jumporg);
self.angles_y = self.ideal_yaw;
// Calculate distance and time
jumpdist = vlen(jumptarg - jumporg);
jumptime = jumpdist / MONAI_JUMPSPEED;
jumpdir = normalize(jumptarg - jumporg);
self.velocity = (jumptime * (DEF_GRAVITY/4) ) * '0 0 1' + (jumpdir * MONAI_JUMPSPEED);
Hopefully it might be helpful to someone else.
 @ Tronyn
#876 posted by golden_boy [46.142.55.90] on 2012/10/03 01:57:21
Sorry, I only rarely read here, but I can be contacted via the e-mail in my profile. I'll gladly reply to mails.
It can be weeks before I check back here.
 Stubborn Fox
#877 posted by madfox [84.26.169.65] on 2012/10/22 23:06:02
Thanks for that bit of code, Sock.
Comes in handy for the RocketJumper I made.
I'm still experimenting with the amphibian.
I made a new model for it, but the code still won't work well.
http://members.home.nl/gimli/dwell.gif
I know it's rather a high catch to invite a monster in Quake
that runs also on land as swimming in water.
For so far I managed it to stand on land and run for the player,
follow it in water turning into a swim pose.
The pitty edge is to get it back into its walk state.
Now it jumps back on land in its swim pose, only turns back into the walk frames after it has bin shot.
The reason for this is that I made an addition in the Fight.Qc
float() HarpCheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
//check we are in the water and also standing
if (self.waterlevel > 0 && self.th_stand == h_stand1)
{
dprint("standing on ground \n");
h_jive1();
harpi_to_harpo();
return TRUE;
}
//check we are in the water and also swimming
if (self.waterlevel < 2 && self.th_stand == h_dwell1)
{
dprint("shallow enough to stand\n");
h_mour1();
harpo_to_harpi();
return TRUE;
}
The first statement gives it a stand attitude on land :
if (self.waterlevel > 0
If I use another number, 2feet 3 chest 4 eyes, the monster won't go back up the land.
The impulse to do so comes in with
harpi_to_harpo();
The second statement gives it a swim pose in water :
if (self.waterlevel < 2
This impulse comes with
harpo_to_harpi();
harpi is in water
harpo is on land
So far it is clear to me.
I try to figure out what's going on when the monster comes out of the water and don't start the stand position.
#878 posted by necros [99.227.223.212] on 2012/10/22 23:47:14
it's difficult to see what to change without seeing more (or all) of the code.
you could try also adding the same checks you have into the first frame of the running sequence.
so what I would do is this:
make the state check it's own function
void() HarpCheckState =
{
//check we are in the water and also standing
if (self.waterlevel > 0 && self.th_stand == h_stand1)
{
dprint("standing on ground \n");
h_jive1();
harpi_to_harpo();
return;
}
//check we are in the water and also swimming
if (self.waterlevel < 2 && self.th_stand == h_dwell1)
{
dprint("shallow enough to stand\n");
h_mour1();
harpo_to_harpi();
return;
}
then add a call to it in the first run frame:
void() harp_run1 =[ $run1, harp_run2 ] {ai_run();HarpCheckState()};
the first run frame is called whenever monsters switch targets or wake up, so it should be more reliable than waiting for it to try to attack.
#879 posted by madfox [84.26.169.65] on 2012/10/23 00:20:59
Right, in addition the corredsponding file only files that matter
There are two modelposes in one file.
The land state and the swim state.
Both are switched in the djive go-in-water and mour come-on-land poses.
harpio.qc
frames$
void() h_jive1 =[ $djive1, h_jive2 ] {harpi_to_harpo();};
...
void() h_jive10 =[ $djive10, h_swim1 ] {};
void() h_mour1 =[ $mour1, h_mour2 ] {harpo_to_harpi();};
...
void() h_mour10 =[ $mour10, h_run1 ] {};
void() harpo_to_harpi =
{
self.th_stand = h_stand1;
self.th_walk = h_walk1;
self.th_run = h_run1;
self.th_die = harpio_die;
self.th_pain = harpio_pain;
self.th_missile = h_attack1;
self.th_melee = harpi_melee;
self.flags = self.flags - (self.flags & FL_SWIM);
};
void() monster_harpio =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/harpio.mdl");
precache_model2 ("progs/slmbal.mdl");
precache_model2 ("progs/h_model.mdl");
precache_sound2 ("player/death2.wav");
precache_sound2 ("fish/bite.wav");
precache_sound2 ("fish/death.wav");
precache_sound2 ("harpi/sight.wav");
precache_sound2 ("enforcer/enfstop.wav");
precache_sound2 ("enforcer/enfire.wav");
precache_sound2 ("knight/khurt.wav");
precache_sound2 ("harpi/idle.wav");
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, "progs/harpio.mdl");
setsize (self, '-16 -16 -24', '16 16 24');
self.health = 200;
harpo_to_harpi ();
walkmonster_start ();
};
void() harpi_to_harpo =
{
self.th_stand = h_dwell1;
self.th_walk = h_swim1;
self.th_run = h_crawl1;
self.th_die = h_die1;
self.th_pain = newharpio_pain;
self.th_melee = harpo_melee;
self.th_missile = h_harp1;
self.flags = self.flags | FL_SWIM;
};
The reason it won't go back to its land state might be the start scene with harpo_to_harpi statement.
So as soon it reaches
void() h_mour10 =[ $mour10, h_run1 ] {};
its original state reminds to harpo_to_harpi
before the walk_monster_start in void()monster_harpio.(?)
I'll try the HarpCheckState(), but doesn't it need more addition to the Harp_Check_Attack?
 Madfox
#880 posted by Preach [77.98.165.95] on 2012/10/23 00:34:49
Add a line to each of the of the h_mour functions where you send out a debug message like so
void() h_mour1 =[ $mour1, h_mour2 ] {harpo_to_harpi();
bprint("I am in h_mour1! \n");
};
Then see how far through the animation sequence it gets. This should help you work out where the problem is.
#881 posted by madfox [84.26.169.65] on 2012/10/23 00:47:04
I don't get any messages in game although I have the bprint in calculated.
protocol 666?
 Falling Through
#882 posted by madfox [84.26.169.65] on 2012/10/23 02:00:48
It looks as if the standing on ground and shallow enough to stand cross over each other.
http://members.home.nl/gimli/frmcount.jpg
#883 posted by necros [99.227.223.212] on 2012/10/23 02:43:46
if you are using Bprint then the messages should always appear. If you are using Dprint, then you need to have 'developer 1' set.
Regarding the monster itself, the one major problem you are having has to do with how swimming is handled in quake.
Walking monsters are able to move into water but swimming monsters are never allowed to move out of water, so no matter where you check, it is impossible for the check to succeed and switch back to land movement.
There are ways to get around that of course, but they are all (at least what I am thinking about in my head) somewhat complex.
The first idea I'm thinking about is changing the land->water check from self.waterlevel > 0 to something like self.waterlevel > 1
This would make it switch when it's much deeper in the water.
Next for the water->land check, I would check the distance to the ground from the monster's 4 bottom corners of the boundingbox to see if there is ground close to it's feet.
Then I would check waterlevel <= 1 and if it checks out, transition water->land.
There might need to be a cooldown timer to prevent it from switching back and forth too quickly too.
The second option would be to use FLY instead of SWIM and then manually stop the monster to rising out of the water.
The best way to do that would be to make a wrapper on the monster's movetogoal calls so that it moves to a helper entity which is set to the player's horizontal position, but who's vertical position is set in such a way to keep the monster under the water.
Using fly would give you more freedom to getting the monster to move OUT of the water, and then you original checks might work out.
Both those options would need a fair bit of code rewriting, unfortunately. :(
 Bprint
#884 posted by Preach [77.98.165.95] on 2012/10/23 09:00:35
I've started using bprint instead of dprint for debugging messages relating to coding, so that there's no way I can forget to remove them!
One way to make the monster can leave the water might be to use the ideas in this tutorial, a hybrid between movetogoal (which won't leave the water) and velocity (which will)
http://www.quaddicted.com/webarchive/minion.planetquake.gamespy.com/tutorial/speed.htm
 More Stubborn Monster
#885 posted by madfox [84.26.169.65] on 2012/10/23 10:31:21
Thanks for the advice!
I have to read the tutorial, but parms like move to goal and velocity are lucide to me.
Not that I don't understand them but the referring code doesn't fit with my knowhow.
It is almost a jack-in-the-box to me how to define a working statement.
As soon as I change the parms the monster works alright,it only comes out swimming on land and I just have to shoot it back in its walk pose.
This works and for sofar I should be glad.
That it is not the bugfree method is something I'm trying to overcome.
 Practical Problem
#886 posted by Preach [77.98.165.95] on 2012/12/01 03:06:42
OK, here's a genuine issue faced when creating the next version of Quoth. A mapper who I will not name has released a Quoth map which uses some entity hacks. In particular they've created a backpack model using the modelindex hack. The new patch precaches fewer models, and so changes which model appears for the modelindex which the hack uses. This breaks the map (from a visual point of view).
Which approach would you choose?
a) Let this entity-hack remain broken to discourage future hacks
b) Insert a piece of code which detects this particular map and fixes the models within it
c) Reorder the remaining precaches so that the backpack occupies the same precache slot in this map
d) Revert the model precache savings, as they are incompatible with existing maps
Remember, there are no right answers. Only wrong ones...
#887 posted by necros [99.227.223.212] on 2012/12/01 05:48:56
create a lookup table that matches the old precache numbers to the new ones?
haha that would be painful to do. :P
#888 posted by Spirit [89.204.137.151] on 2012/12/01 09:54:13
name it quothX.Y and tell people to state the tested quoth version(s) in their readme from now on. consider all existing maps requiring quoth2.
 Not Really Related But A Selfmade Problem:
#889 posted by Spirit [89.204.137.151] on 2012/12/01 10:02:43
releasing quoth2 as quoth was annoying already (from a quaddicted viewpoint). I really do not want to replace it again and pretend comments and ratings are for the new version.
I guess one would need to add an dependency option of 'provides', so eg quoth2 provides/fulfills the dependency 'quoth'.
or how about calling them "quoth_pak1", "quoth_pak2", etc.
 Look-up Sir, Arrgggh!
#890 posted by Preach [77.98.165.95] on 2012/12/01 10:23:40
That's more or less what option c) is, except you only match this particular model to the index it once had. If you're precaching fewer models, it's obvious that you can't do that for every model, so the solution would not be sustainable if this hack was common.
I thought the backpack would be reasonably easy to fix like this because it's in that big list of guaranteed precaches in world.qc. You'd just look at the list and move the backpack precache down as many precaches as it takes. On looking at it, this might not work; unfortunately the backpack is one of the last things to be precached. The number we'd have to give it would belong to the "variable precaches region" which changes depending on which entities the map includes.
You could try to add a wrapper to the precaching function which counts the number of calls, and then precaches the backpack after the right number of entries. There's two problems: First you need to filter out multiple calls to precache the same file (which is hard given QC's lack of support for arrays). This can be done with some effort though, because we know exactly how many precaches we need to remember - the number between the guaranteed precaches and the desired precache value for the backpack.
Then you need some way of dealing with the possibility that not enough models get precached, and so the backpack is never precached either. In QC you don't have any way of telling how many more entities there are to spawn, and when the last spawn function has run, you no longer have the ability to precache models. So you can't predict ahead of time you're in the state where the backpack won't get precached. Any solution for this case would need to be based on the idea of working round the backpack model missing its precache, which is actively detrimental.
So the only proper way to get this trick to work is to sniff which map is being loaded by some other means, and fix it up then. At this stage b) is probably more attractive.
 Spirit
#891 posted by Preach [77.98.165.95] on 2012/12/01 10:29:05
There are lots of enhancments in new versions of a mod that benefit existing maps - like the rebalancing of annoying monsters, or the fixing of occasionally occuring bugs. So we need backwards compatibility.
#892 posted by negke [31.18.186.11] on 2012/12/01 10:29:19
Said mapper may also have included two versions of the hack to make it work on both Quoth 1 and 2, so if a new release were to address compatibility issues, it would probably need to take care of two modelindex shifts (unless Quoth 1 didn't change anything about it).
 Yes
#893 posted by Preach [77.98.165.95] on 2012/12/01 10:46:18
I noticed that, and wondered if that might have been a hint to whoever it was not to indulge in that kind of behaviour. For the record, using a mapobject_custom is a much easier way to get the model you want (they aren't static entities by default). That would only require the hacky version in quoth 1, and then using a designed entity for other versions will be forward compatible.
 Preach
#894 posted by Spirit [80.171.143.236] on 2012/12/01 10:53:59
Rebalancing monsters IS breaking backwards compatibility!
(Aaaaahh change!)
 True
#895 posted by negke [31.18.186.11] on 2012/12/01 10:55:31
There should have been an item_custom entity to begin with.... Which new model does it display anyway?
Btw, since you're working on a new version of Quoth, do you have a list of desirable features mentioned over the years or something like that? Obvious things that Quoth is missing for no good reason. Not going for a public feature request discussion, just interested.
 The List
#896 posted by Preach [77.98.165.95] on 2012/12/01 11:11:16
To make clear, the current patch is limited in scope, and the specific limit I am sticking to is no new entities. I do have other ideas for what might go into a future version of Quoth, custom items is not on it though...It currently displays a head gib with a very weird skin.
Spirit, backwards compatibility is not the same as identical behaviour, else fixing bugs is prohibited because the new patch doesn't crash to the console. For gameplay, I take backwards compatibility to be: from any map or set of circumstances that a player could complete a map in the previous patch, they still can in the new patch with no more difficulty. As someone pointed out in the Quoth 2 thread, making monsters weaker does not affect that. Obviously there are other measures of backwards compatibility that have to be considered, and visual fidelity is one.
#897 posted by onetruepurple [91.240.47.30] on 2012/12/01 11:33:07
Is the protocol 15 precache limit really that big of a problem in 2012?
 Steam
#898 posted by Preach [77.98.165.95] on 2012/12/01 11:46:43
I'd hazard a guess that the majority of people with quake installed right now use protocol 15, because they bought it bundled on Steam and don't know anything about custom engines. I'm not imagining that every mapper will create maps that run on all engines. Still, if some mappers might want to, the mod should do all it can to enable that.
#899 posted by onetruepurple [91.240.47.30] on 2012/12/01 11:50:17
That's true, but if they know about custom maps in the first place, then knowing about custom engines is just a few inches away.
Unless it's not possible to run a custom engine with Quake on Steam?
 Barriers
#900 posted by Preach [77.98.165.95] on 2012/12/01 11:55:58
I think you can, but each extra barrier to running the map is gonna turn away some fraction of your audience.
 Follow-up
#901 posted by Preach [77.98.165.95] on 2012/12/02 11:33:58
If you did want to design a mod where it was clear to mappers what they were free to touch and what you were reserving for future modification, then you might be able to use some of the tricks in an article I've just posted:
http://tomeofpreach.wordpress.com/2012/12/01/whats-in-a-name/
For people who think that it's all a bit crazy and worry for the future of Quoth, don't. Firstly it's too late to do all of this for Quoth, you'd need to have done it before you release the first version and people start making maps. Secondly, Quoth probably doesn't need it because it's fairly slow moving. The private fields stuff would be more useful when you're releasing new versions each month or something, keeping new features private while you're messing with the design, like an "under construction" gif.
If you still think it's a bit paranoid, hold on, because there's a much more interesting use of these field name tricks coming up.
#902 posted by necros [99.227.223.212] on 2012/12/02 15:41:36
That... Is very interesting. Would have been useful to protect stuff for sure. Although if you're going to limit things in that way then you should try to provide ways to do those things explicitely.
Could someone explain mechanically how Quake's monster stun effect works? Is it like Doom's where monsters have a percentage chance to be stunned, or does it go off the amount of damage cause etc?
#904 posted by Spirit [80.171.154.52] on 2012/12/02 20:24:24
I think it happens on specific animation frames
 (i Guess You Mean The Sudden Attack Cancelling Effect)
#905 posted by Spirit [80.171.154.52] on 2012/12/02 20:24:43
 Percentage
#906 posted by Preach [77.98.165.95] on 2012/12/02 22:23:20
It's something that varies from monster to monster, and it depends on a lot of things:
Random chance
Amount of damage
Time since last attack
Skill level
Each monster has an individual function to decide what to do, I'll explain two contrasting ones:
The grunt is on the weakest end of things. The first hit it takes will always send it into pain. At that moment one of the pain animations is selected, and it's pain_finished field is set so that it can't go into pain again for a short time. The pain_finished time for grunts is barely long enough for the pain animations to complete. Amount of damage has no effect.
The shambler is on the opposite end of things. When it takes a hit, it generates a random number between 0 and 400. If the amount of damage is less than the number generated, it ignores the hit. Otherwise it goes into pain, and sets pain_finished to 2 seconds into the future.
In between these two extremes there are lots of variations. The pain_finished time is unbreakable, but after that there is usually some amount of damage which guarantees a pain animation (e.g. we see the shambler takes 400, the death knight is only 30). Nightmare skill has a global effect - the minimum gap between pain animations is 5 seconds for everything.
ic, interesting. It certainly seems somewhat random but a lot less so than Doom's...
Cheers :)
 Overlaps
#908 posted by Preach [77.98.165.95] on 2012/12/03 10:57:32
As promised, the second half of yesterday's article, with a more sensible use for private and hidden fields, after introducing overlapping fields.
http://tomeofpreach.wordpress.com/2012/12/03/overlapping-fields/
 Re: Practical Problem
#909 posted by Scampie [72.12.65.92] on 2012/12/03 20:27:20
I know this is a hack, but could you not add special consideration to 'info_notnull' that when it has a 'model', you search for other entities with the same 'model', and set it's 'modelindex' the same?
So if I have a:
"classname" "info_notnull"
"origin" "# # #"
"think" "PlaceItem"
"nextthink" "0.2"
"touch" "BackpackTouch"
"model" "progs/backpack.mdl"
"modelindex" "#"
We'd look for another entity which already was 'model' 'progs/backpack.mdl', and use it's modelindex as our info_notnull's. This means the info_notnull would have to be later than an actual backpack (or whatever we were trying to copy)... but wouldn't that make the designer setting the correct modelindex irrelevent, and all he'd need to do is set a correct model?
 Modelindex
#910 posted by Preach [77.98.165.95] on 2012/12/03 21:37:49
Yeah, there's really no need to be doing anything with the modelindex if the mod supports custom model setting. Thankfully Quoth provides that with the mapobject_custom entity - which will also precache whichever model you supply it so you aren't restricted to models the mod already uses. The mapobject_custom is basically an info_notnull in every other way, so if you were to apply other hacks to it they'd work fine.
I stopped short there of saying "go ahead and use hacks", as they can cause problems, but I do still keep them in mind when designing things. For example, one of the features I've considered for Quoth is aggressive entity optimisation. This would basically be runtime consideration of which entities don't actually need a full entity slot to themselves (yet), along with a way to let entities share slots for the time being.
The path_corner is the simplest example of how this would work. Even with all the exciting extra features added to them in Quoth, you only need about half a dozen fields to store everything relevant about a path_corner. I've written code that will take those vital fields and stash them into one of four field-sets, making an entity with a "library" of 4 path_corners. The pool of library entities also doubles as the active path_corner entities, which are dynamically generated as a monster heads towards one.
So if this is all done and working, then why isn't it going into 2.2? The reason is hacks. The logic that says you only need 6 fields to store the relevant info from a path_corner breaks down if someone performs any kind of hack on the path_corner. Because there's no limits to what might be hacked, you can't predict what extra fields you'd need to store to restore the hack to working order, and the fact that potentially you'd need to store any field means there's no space to store even a second path_corner. Even if you could, dynamically generating the path_corner is equally toxic to potential hacks, as the path_corner might not exist at the vital moment the hack is to be triggered.
I can see two ways round this: one would be to create a global opt-in flag like the model optimisation flags: the flag would mean "This map is free of hacks, so go ahead and aggressively optimise it". The alternative would be a local opt-out flag on entities, meaning "don't optimise this entity, I'm performing a hack on it!". While I'd prefer the latter, I suspect it wouldn't be backwards compatible.
Some might say that surely path_corner is a safe thing to optimise, that nobody would hack. However
1) There's already a hack involving them
2) Imagine the same principle applied to unspawned monsters
The take-home message is this: Map hackers of the world, you are being considered, but you make it hard on us!
 Is That So?
#911 posted by onetruepurple [91.240.47.30] on 2012/12/03 21:53:04
The mapobject_custom is basically an info_notnull in every other way, so if you were to apply other hacks to it they'd work fine.
Applying the "give the player a DBS" fields from my info_notnull to my mapobject_custom made the backpack model not appear.
{
"classname" "mapobject_custom"
"origin" "320 184 -244"
"model" "progs/backpack.mdl"
"skin" "14"
"think" "InitTrigger"
"touch" "BackpackTouch"
"items" "2"
"netname" "Double-barreled Shotgun"
"nextthink" "0.2"
"targetname" "pack_dbs"
}
 InitTrigger
#912 posted by Preach [77.98.165.95] on 2012/12/03 22:02:45
InitTrigger is to blame there, it intentionally hides the model of whatever it is run on, so that you can't see triggers.
 I See.
#913 posted by onetruepurple [91.240.47.30] on 2012/12/03 22:10:18
Any way around it?
#914 posted by necros [99.227.223.212] on 2012/12/03 22:13:11
the flag would mean "This map is free of hacks, so go ahead and aggressively optimise it"
this isn't that bad an idea... like setting a strict doctype.
 Two Replies In One
#915 posted by Preach [77.98.165.95] on 2012/12/03 23:15:56
onetruepurple: try swapping the classname and the think.
necros: yeah, I think it's what will have to happen. Maybe you can have the local opt-out flag as well. Opt-in flag means: "I will let you know when I'm hacking", opt-out means: "This is a place I am hacking"
 What Else
#916 posted by ijed [200.73.66.2] on 2012/12/05 23:57:09
Other than a missing precache, causes Quake to crash without error?
Dusting off my coding skills and this has me stumped.
No errors in the compile either.. although I am running FTEQCC. It's definitely something I've done recently though.
 Difficult
#917 posted by Preach [77.98.165.95] on 2012/12/06 00:31:41
Best advice I can offer is call traceon() in the worldspawn function, then run with -condebug on. You'll get a massive log file, but you probably only need the last few lines to find out what runs immediately before the crash. Otherwise, maybe try a few different engines, darkplaces will often tell you something that other engines don't.
#918 posted by rj [82.3.233.25] on 2012/12/06 00:47:21
infinite while loop? had that a few times
 Ijed
#919 posted by Mandel [80.217.68.43] on 2012/12/06 06:39:39
Another crasher: whatever's happening on e2m2 when you pass the front gate without shooting both buttons on easy skill.
 Thanks!
#920 posted by ijed [200.73.66.2] on 2012/12/06 13:55:54
Will get this figured out.
 Overlapping Fields
#921 posted by necros [99.227.223.212] on 2012/12/12 15:28:37
Preach,
So recently, I treat QuakeC as if it were an OO language in that I ALWAYS create new .variables for all entities.
I do this mainly for readability/clarity reasons after getting burned when trying to make sense of some older code that was using things like t_width and lip all over the place.
Of course, now every entity has like an extra 100 variables attached to it. While it's unlikely to really impact the code much (it's not like we're lacking memory or processing power here) it does bug me a little in that it's not really the right thing to do for this language.
So... would the proper course of action be to declare a handful of invisible fields:
internal_float1__ ... internal_float10__
internal_vector1__ ... internal_vector5__
etc...
and then overlap the same fields with unique names?
 Yeah, I Guess
#922 posted by Preach [77.98.165.95] on 2012/12/12 20:58:38
It could work, but you've got to be really careful that you're never overlapping fields that will cause problems. You don't need to give them names like internal_ etc, you can just pick one name as the original and overlap the others on that.
Doing this kind of overlapping in monster code might be safest. Make sure each monster has its own QC file, and define the overlapped field name at the top of the monster's own QC file. Then you can make sure all use of these fields is localized to functions in the one QC file. To be doubly sure, instead of using the "var" keyword to overlap, use a #DEFINE macro to give the field its name, and then undefine it at the bottom of the file. Then you only need to watch out for other QC files calling your functions (and map-hacks).
What would be really nice would be a sort of QC++ compiler which creates the idea of a "class". It would let you subclass entities, have functions that only accept particular classes of entity, and prevent you accessing entity members which aren't defined for that class (or parent classes) at compile time. Then the compiler would overlap private fields for you safely.
This isn't quite as crazy as it sounds, the original C++ compilers were source code transformers which output C code and then called a C compiler to build it. A fun project for someone who wants to learn Lexers and Parsers...
 Wah
#923 posted by ijed [200.73.66.2] on 2012/12/13 22:23:41
After rolling back everything - models, sounds, code, maps I still got the crash on map load.
So I open up the map and clean out the values I'd added to control the enemy in question, and that solved it.
pose 0
skin -1
cnt 0
One of those was the guilty party I'm assuming the skin value - I was using -1 as 'random'.
(this is about a crash I mentioned earlier in the thread, thought it might be of passing interest)
 Yeah
#924 posted by Preach [77.98.165.95] on 2012/12/14 00:29:43
I can imagine how that might cause a crash, yeah. Setting fields to zero in a map should do nothing at all, fields are zeroed to begin with. The -1 on the skin might do it though! The engine probably uses -1 as an offset into the skins array, and reads some random memory just before the site of the model data. If you still want to live dangerously and use -1 as the "random skin signifier", you can probably do it just by altering your QC a little - handle the -1 case and randomly select a skin before any call to setmodel.
#925 posted by metlslime [159.153.4.50] on 2012/12/14 01:52:21
With a skin of -1, MSG_WriteByte will coerce the value to a unsigned char, which I think gives it a value of 255? Then the client gets the 255 and and uses that index to look up the gltexture in an array. This array access is probably out of bounds, causing the crash.
 Aha
#926 posted by ijed [200.73.66.2] on 2012/12/14 14:03:10
So when I cleaned up the code and put setmodel / setskin in the right places it broke...
I had to delete a lot of stuff, but I don't see it as wasted time - now I can build it much quicker and better.
It's for an undead enemy that 'hatches' from dead marine corpses - the unlucky guy's own skeletal and muscular structure, minus the skin.
 OOB For Fun And Profit
#927 posted by Preach [77.98.165.95] on 2012/12/14 19:42:45
Another fun way to go out of bounds with skins is to use a skin coordinate which goes off the edges of the skin. GL engines handle this fine, they start tiling the skin which is very handy. Unfortunately software engines just do blind pointer arithmetic, and so start rendering the rest of the model data as if it were the skin...
 Well
#928 posted by ijed [200.73.66.2] on 2012/12/14 20:29:41
I understand the problem well enough now to think of a workaround. A lot of the bad practices in Quake (mapping, sounds, coding etc) aren't really documented anywhere clearly and exist as generally known knowledge, making it hard to know it all...
Thanks for the help :)
 Wicked Map
#929 posted by mechtech [65.190.42.20] on 2012/12/23 01:23:08
After playing Something Wicked This Way Comes. I started thinking about the expansion of the BSP format, the VIS times involved in expansive maps, and the task of managing large maps in an editor. Has anyone tried to create an engine/QC that would allow information sharing over multiple bsp files? I think that making the BSP format larger is one way to make larger maps but the time to compile/test/compile is going to be a problem. Fixing one end of the pipeline at the expense of the other. Wicked could have been split in two, both halves in memory and the textures loaded, a transition would be almost instant. I'm not a coder but that seems better than making vis run for weeks.
 Well
#930 posted by ijed [200.73.66.2] on 2012/12/26 18:33:17
Vis doesn't need to run for weeks. What Quake is really missing is its own method for doing detail brushes.
If you look at those massive towers in something wicked, you'll see that they're both func_wall - noclip out of the world and they'll vanish.
If those had been part of the vis process then it would have taken significantly longer.
What the RMQ engine does to enable stupidly big and complex func_walls is to fix the entity flicker bug.
Normally, if you try to have a func_wall that stretches across various vis leafs, it flickers in game as the player moves between the different leafs.
With this bug fixed, you can make a func_wall that spans across practically a whole level, with lots of small details, curved surfaces or whatever and doesn't impact vis time at all.
There is of course a trade off in performance, but seeing as vis was designed to work on 1997 hardware - with 8K of ram - this point is pretty much moot.
These tools aren't automatic though, and a certain amount of technique must be learned in order for them to be used.
I'm far too impatient to vis a map for anything over an hour - and I don't want levels that are choppy either.
Is work continuing on the RMQ engine? I hope it does because it's performance is so much higher than other engines like Fitz which is much more interesting to me than extra eye candy :/
#932 posted by sock [200.82.42.123] on 2012/12/26 19:47:56
I know a lot of mappers use func_wall like detail but I always have problems with their shadows when aligned to world geometry. An object which is part of a wall will cast better shadows than the object as a func_wall placed against a wall.
Personally I think the compiler tools could do with some upgrades more than allowing mappers to create long range shooting galleries.
* Consist lighting across bmodels and geometry.
* bmodels having a minlighting options so it is easier to get rid of solid black surfaces.
* Having external light maps so the lightmap density can be increase (would need engine support)
* Being able to having textures with phong shading (probably need a new compiler tool to split the surfaces off in a separate area of the BSP for the light tool to work with them.)
Some of the most radical visual/mapping upgrades to Q3 was when Yndar was working with the compiler tools. I am sure it was the same when Bengt Jardrup worked on the Q1 tools.
 External Lightmaps
#933 posted by necros [99.227.223.212] on 2012/12/26 20:02:23
this is interesting... what exactly is it, and how does it work? ie: external vs internal, is it just upping lightmap resolution?
I am sure it was the same when Bengt Jardrup worked on the Q1 tools.
Pretty much. It was a huge loss when he moved to q2. He consolidated like a dozen different compilers together and his work on the light utility in particular was amazing, not to mention vis progress saving.
 RMQe
#934 posted by ijed [200.73.66.2] on 2012/12/26 20:32:31
Don't know - Mh was working on it.
The lack of shadows can be an issue, I tend to avoid it for large objects by placing a simplified mesh inside the func_wall - just a block usually, which won't upset vis but still give shadows.
Not perfect shadows, but the resolution of the shadowmap isn't great in any case and small details are usually lost.
For external lightmaps do you mean direct access to the lightmap texture? I think it can be extracted from the bsp, though not sure how.
And yeah, Bengt did amazing work to consolidate and improve everything.
#935 posted by sock [200.82.42.123] on 2012/12/26 22:43:24
@necros, external lightmaps are large (usually tga) files which only have light data. They are external because the internal bsp format only supports small light maps. By increasing the size of the maps the lightmaps on objects can be bigger (less fragments) and high density for remapped on to the relevant compiler surface. To create this feature would require a lot of effort to include in the Q1 compiler tools.
The most linked article on external light maps! :P
http://sgq3-mapping.blogspot.com.ar/2009/01/using-hi-resolution-external-lightmap.html
Probably the most annoying thing about light maps is that they are rarely consistent across multiple object types (brushwork, models, entities) and will produce different results depending on how the compiler tools organize/sorts them. Even Quake 3 with all of its fancy features still has different compiler pipelines for models and brushwork which can cause strange lightmap errors.
Some examples of weird lightmap errors:
http://www.quake3world.com/forum/viewtopic.php?f=10&t=46294&p=901394&hilit=#p901394
#936 posted by necros [99.227.223.212] on 2012/12/27 04:18:16
That looks similar to making lightmaps in doom3.
I guess the compiler would need to both export the lightmap as a texture AND output uv information for the bsp faces being mapped?
I don't know how likely someone can do that for q1...
Looks very similar to what you could do in ut2k3, making entire levels out of meshes that were pre-lit in Max/Maya.
crappy screenshot
Was a gorgeous effect if used properly, fantastic lighting and such (on the environment at least), given that ut2k3 didn't have any kind of light bounce and meshes were purely vertex lit... problem was building an entire map in Max was a bastard :(
#938 posted by necros [99.227.223.212] on 2012/12/27 20:55:20
Yeah, that was the same thing for d3. I found building maps in max to be much easier too, because you could make complex shapes much more easily and utilize the scripting capabilities to quickly build stuff.
 Question
#939 posted by ijed [200.73.66.2] on 2013/01/02 18:08:19
Do models have their own centre point that Quake somehow reads?
I'm trying to swap models and my enemy is getting stuff stuck in the floor. I set the bbox manually, but it seems to get confused depending on when I make the walkmove! check.
Might be better off just setting model to null until it needs to be alive and using a .entity for the other version.
 I Know
#940 posted by ijed [200.73.66.2] on 2013/01/02 18:10:18
There's an 'eye plane' or something like that, but AFAIK it's just some helper that Qme included and didn't actually do anything.
#941 posted by necros [99.227.223.212] on 2013/01/02 19:43:06
There is an origin on quake models. You need to have the model's feet 24 units below the model origin in order for it to line up with the ground.
 Ok
#942 posted by ijed [200.73.66.2] on 2013/01/02 20:15:39
Need to throw more DropToFloor experiments at it.
What's 24 units in normal dimensions? I googled a bit and this: http://www.gamers.org/dEngine/quake/QDP/QPrimer.html
Tells me it's 72cm...
Feel like I should know all this stuff, but its the first time I've had this problem - or maybe just the first time I've noticed since I'm mixing legacy with new assets in the same monster.
#943 posted by necros [99.227.223.212] on 2013/01/02 20:19:34
The engine bounding box plays a role in determining the position of the model as well.
eg: '-16 -16 0' '16 16 64' is not the same as '-16 -16 -24' '16 16 40'
 Aha
#944 posted by ijed [200.73.66.2] on 2013/01/02 20:29:08
That's probably it then - I've been getting odd behaviour and after the previous problem tried changing the order of where I was defining the box / changing the model asset.
Sure enough, things got free that weren't stuck before.
Weird how it was done. Especially using imperial measurements.
#945 posted by necros [99.227.223.212] on 2013/01/02 20:38:28
hold on... i might be wrong on my last post... it's been a while since i've messed with models and bboxes too. :S
 Heheh
#946 posted by ijed [200.73.66.2] on 2013/01/02 20:48:25
Well, I'm going to be redoing the mesh from scratch anyway, but want to get something lashed together in the code for now anyway.
So will have to experiment and see what works.
FYI it's based off that model you sent me some time ago, although I've modified it pretty heavily into something else now, next step being an updated mesh...
 Got It
#947 posted by ijed [200.73.66.2] on 2013/01/02 22:47:24
Thanks for the help :)
 New Question
#948 posted by ijed [200.73.66.2] on 2013/01/09 23:38:38
How do I get a flyer to prefer to be higher than the standard 'eye level' fly height?
Searching around, it seems that movetogoal is the answer, but this is in the C code apparently and I want to stick to qc.
I don't exactly want a B0b vertical dodge - although that could be useful as well for when it's in hunt mode.
#949 posted by metlslime [166.137.191.15] on 2013/01/10 00:18:59
Look at rubicon 2 source, I have a hard-coded min and max altitude that can easily be changed. The trick is using an invisible dummy entity as .enemy to trick movetogoal into seeking the desired altitude.
#950 posted by necros [99.227.223.212] on 2013/01/10 01:19:43
 Great
#951 posted by ijed [186.37.203.37] on 2013/01/10 10:58:27
Thanks guys.
 Perfect
#952 posted by ijed [200.73.66.2] on 2013/01/10 13:02:54
Lots of useful stuff to learn from.
Insightful to see two different implementations that work with slightly different approaches.
 Oh Dear
#953 posted by Preach [77.98.165.95] on 2013/01/19 00:28:54
Oh no, another blog post. If you're using the hipnotic rotating entities, you might want to go grab this fix...
http://tomeofpreach.wordpress.com/2013/01/18/sub_normalizeangles-bug-squashed/
#954 posted by necros [99.227.223.212] on 2013/01/19 01:28:00
Thank you!
 Wait
#955 posted by necros [99.227.223.212] on 2013/01/19 01:29:13
did you have an old version of hipnotic? mine already had that fix in.
 Maybe...
#956 posted by Preach [77.98.165.95] on 2013/01/19 11:48:52
I was working on Quoth when I noticed it, so that might have been out of date.
 Stack Overflow
#957 posted by madfox [84.26.94.131] on 2013/01/29 21:20:49
I'm puzzled about monster behaviour.
After setting the qc for self.th_stand, self.th_walk and self.th_run, self.th_pain and self.th_die I'm left with the self.th_melee and self.th_missile.
As long as I take the "SUB_NULL" everything goes fine, except the monster can't attack.
As soon as I give these parms a function the game returns them as
ai:CHeckAnyAttack
fight:CheckAttack
monster:monster_atk1
stack overflow.
Maybe it is my wrong assumption a monster can be added with only changing the monster's qc and leaving the ai and fight.qc aside.
Earlier I added monster with the enforcer.qc and there were no console messages.
I know I have to change things in ai.qc and fight.qc, as I did by adding a CheckAnyAttack in ai.qc and a CheckAttack in fight.qc.
Still the compiler sees no wrong but in game the console hangs on stack overflow.
 Stack Overflow
#958 posted by Preach [77.98.165.95] on 2013/01/29 22:16:26
Stack overflow often comes from two functions calling each other in a loop that cannot be escaped. CheckAttack will run any function you put in th_missile or th_melee. If monster_atk1 calls CheckAttack, then the QC just goes back and forward between the two. The fix is to make sure that you don't call CheckAttack in monster_atk1.
What can make it harder is that you might not run CheckAttack directly - you might run ai_run which runs CheckAnyAttack which runs CheckAttack. So post exactly what your monster_atk1 does and we can see how to break the loop...
 Acracadabra
#959 posted by madfox [84.26.94.131] on 2013/01/30 00:22:45
The qc is a bit long so you find it here
As i started to make changes to the ai.qc with the CheckAnyAttack and the fight.qc with CheckAttack, I tried again with a cleansource.
Proqcc asks where def.qc 699 exp ; found
Ftecqc responds with no error, but on console
The idea was a quake1 Orb, that has a melee missile attack and a jump function like the demonfiend.
 Read-only AI
#960 posted by Preach [77.98.165.95] on 2013/01/30 00:41:25
It's a good exercise to try and write a self-contained monster, which only calls the ai functions but doesn't alter them at all. It's also better for making a monster that "feels" like the originals. So stay strong, let's fix the file.
You are calling ai_run in all your attack functions, which isn't always the best plan. The problem with ai_run is that it looks like "this is the function I call to move n steps forward". It's actually more like "this is the function to look for something new to do, and run forward if I can't find anything".
So ai_run is looking for something better to do than just run, and it tries to attack. When it decides it can attack, it runs orb_jump1 to get the attack started. Then trouble: orb_jump1 calls ai_run again! So ai_run looks for something better to do that it was doing, and decides to attack...
...and the loop goes on until you crash.
If you look at demon.qc, you'll see that it doesn't use ai_run anywhere in the attack functions. When it needs to move, it uses ai_charge instead. There are other ways to get round the problem, but replacing ai_run with ai_charge in your attacks is a simple fix to start with.
 Yeah
#961 posted by madfox [84.26.94.131] on 2013/01/30 01:36:46
That's what I was looking for!
I didn't see the ai_charge. I kept changing the ai and fight.qc with the loop result.
Thanks for your clear explanation, after a few days I thought the orb could only crash.
 Grr, Arg
#962 posted by Preach [77.98.165.95] on 2013/02/24 21:08:21
Darkplaces is the Internet Explorer of custom engines - it has features that nobody else offers, but creates awkward incompatibilities at the same time. Today's bugbear: it changes findradius so that non-solid entities are included in the search results. This makes it possible to create invisible ghost monsters in Quoth with a rocket in the wrong place...
#963 posted by necros [99.227.223.212] on 2013/02/24 21:19:40
yeah, i don't try to support it anymore. just too many things broken.
 Look Through The Sv_gameplayfix_* Cvars
#964 posted by Supa [50.193.192.106] on 2013/02/25 00:16:04
The one you want to disable in this case is sv_gameplayfix_blowupfallenzombies
 Total Opt-out
#965 posted by Preach [77.98.165.95] on 2013/02/25 01:51:16
Is there a cvar that says don't do anything present or future which messes with the QC? It wasn't hard to tweak the code to work around this - the cost is in spending the time testing in darkplaces for bugs that don't occur elsewhere, reproducing them reliably and working out what the engine does differently. I'd add "sv_gameplayfix_optout 1" to quake.rc in an instant.
 No Opt-out
#966 posted by LordHavoc [50.193.192.106] on 2013/02/25 04:03:40
I have no plans for an "optout" cvar because it's like taking a sledgehammer to a nail, it isn't the right solution to the problem.
The right solution to the problem is one where users don't have to do anything.
I'm still evaluating the right solution.
 Arrays
#967 posted by sock [186.108.77.104] on 2013/02/27 14:56:37
Is there a QC compiler that supports arrays?
#968 posted by Spirit [80.171.7.56] on 2013/02/27 15:46:23
#969 posted by Spirit [80.171.7.56] on 2013/02/27 15:46:23
 Fteqcc!
#970 posted by ijed [200.73.66.2] on 2013/02/27 18:39:02
Yes, it's great :)
 Compiler
#971 posted by sock [186.108.77.104] on 2013/02/27 19:56:01
@Spirit, I am using that already, thanks :)
 V_angle / Mangle
#972 posted by sock [186.108.77.104] on 2013/02/27 20:11:40
I am trying to make an object look directly at another object. I want the v_angle/mangle (Pitch/Yaw/Roll) but I can't work out how to get them.
I know about vectoyaw:
dir_float = vectoyaw(destination.origin - source.origin)
This returns the Yaw angle, but I want the Pitch angle as well.
Any clues?
 Pitched
#973 posted by sock [186.108.77.104] on 2013/02/27 20:57:36
For some reason the pitch is reversed. I got the following to work but not sure why the pitch needs to be fixed.
vector vec = destination.origin - source.origin;
vector vec_dir = vectoangles (vec);
vec_dir_x = 360 - vec_dir_x;
 Protocol Question
#974 posted by Mandel [80.217.79.210] on 2013/03/01 19:33:04
Which maps, mods, or demos use all or most of the fitzquake protocol features? I've added fitzquake support to my demo parsing code and would like to exercise it a bit for the sake of quality.
 DarkPlaces Sv_gameplayfix Cvars Are Now Opt-in, And New Build Posted
#975 posted by LordHavoc [50.193.192.106] on 2013/03/02 06:18:02
Posted a new build of DarkPlaces today with sv_gameplay fix cvars off by default (the disruptive ones, anyway), and some bugfixes for hipnotic (hip2m3 now completable) and other maps.
I have fitzquake protocol support in the works but not the time to finish it right now, I don't understand why fitzquake uses a protocol different than the QUAKEDP protocol that it clearly borrowed several bits of code from...
#976 posted by Spirit [80.187.110.71] on 2013/03/02 08:34:38
thank you very much!
 @LordHavoc - DarkPlaces Constructive Criticism
#977 posted by Baker [69.47.162.203] on 2013/03/03 01:55:58
Everything has to be something.
Pushing the limits of future ideas is not something to be apologized for. Especially if you are doing it for free.
Mental exercises of the future are something anyone can do. You express these in code, something few to no one can do.
You've done it, do continue to do it and everyone sensible is inspired by it, everyone talented draws insight from your work.
Everything has to be something.
More importantly, BUT ** everything has to be something. **
DarkPlaces cannot both be an engine of the re-imagined future and a conservative engine of the past.
If you try to go there, you'll fail on both fronts and lose your identity in the process.
Everything has to be something. If DarkPlaces tries to be everything to everyone --- it is going to fail more spectacularly than any engine Quake has ever seen.
It is ok to be an engine that thinks of ONLY how things should be and never of how they are.
If you try to change that thought process, it will not lead to happiness. Your head is in the idea of a yet unwritten better future.
Give that up and it will most certainly break your heart. And make the world a worse place.
Bear the slings of arrows of re-imagining how perfect QuakeC and a perfect Quake engine might look EVEN if it breaks expectations.
Every engine author can do the conservative engine thing. This isn't why DarkPlaces is interesting. Just don't expect everyone to like "interesting" --- that isn't in human nature.
/End tl;dr post
 Hey Sock
#978 posted by ijed [200.73.66.2] on 2013/03/06 13:12:18
How did you go about your particle field controls in ITS?
I've got an emission system implemented that can throw sprites, bsps and models, but was wondering about better particle controls.
The main thing I'm wondering about is movement - I can just attach particles to an otherwise invisible emission, but was wondering what method you used, and if it'd be cheaper / better / faster.
Cheers :)
 @ijed
#979 posted by sock [186.108.77.104] on 2013/03/06 14:07:17
Posted reply in ITS mod thread. If you have anymore questions let me know, will be glad to help.
 Thanks, Just Replied There
#980 posted by ijed [200.73.66.2] on 2013/03/06 15:02:35
 DarkPlaces
#981 posted by sock [186.108.77.104] on 2013/03/08 14:13:12
Is there any way to detect if DP is active from QC? Is there a function I can test exists and then supply different fog parameters?
Fitz engine fog
<density> <red> <blue> <green>
DP engine fog
<density> <red> <blue> <green> <alpha> <mindist> <maxdist> <top> <fadedepth>
I can't add the extra parameters to fitz it produces an error, while in DP the DEFAULT parameters fog out the sky. /sigh
Any ideas?
 DP Cvar
#982 posted by sock [186.108.77.104] on 2013/03/08 15:02:26
Does anyone know of a specific DP Cvar value I can check? (I tried version but it is a string which is impossible to check)
 DP Only Cvar
#983 posted by sock [186.108.77.104] on 2013/03/08 15:26:28
Found the answer, QC example below:
float dpactive;
if ( cvar( "pr_checkextension" ) ) {
dpactive = TRUE;
}
else dpactive = FALSE;
 Fix Your Ugly Brace Style PLEASE!
#984 posted by czg [212.16.188.76] on 2013/03/08 15:27:30
 But That's A Cool Snippet Tho!
#985 posted by czg [212.16.188.76] on 2013/03/08 15:43:47
 Feature Detection
#986 posted by Preach [87.139.242.110] on 2013/03/08 18:33:02
In theory other engines might implement checkextension at some point, so you should probably be testing for features in darkplaces, rather than for darkplaces itself. It's like "feature detection" as opposed to "browser detection" in web design - that IE analogy is working overtime today (which I'd like to add was too unfair on DP, especially given how responsive LordHavoc has been to our needs!)
I've wanted for a while to be able to detect .alpha support on engines, to create entities which fall back to safer models on engines without it. At the moment it would only be darkplaces which gets the alpha-supported version, which makes the feature a bit too niche.
 Sv_gameplayfix_
#987 posted by negke [31.18.175.98] on 2013/03/08 18:55:44
Can't get more DPish than that, I suppose.
 Enginer Developers
#988 posted by sock [186.108.77.104] on 2013/03/08 19:21:10
I honestly wish ALL engine developer would decide on a standard way of implementing features. Like for example fog, engine detection etc. As much as it is cool that everyone wants to do different things, trying to make content that works on multiple engine is just frustrating.
I don't want to create a preferred list of engines that work with my Quake content but engine coders really are shooting themselves in to the foot over this.
I choose "pr_checkextension" because it is highlighted at the top of the dpextensions.qc file (had to download a 220mb DP mod to get the file) as something to detect DP by. Maybe LordHavoc can say which variable we should all check by.
#989 posted by Spirit [80.187.111.49] on 2013/03/08 20:08:07
at least all normal engines have the same syntax but wait until you find out that the rendering of the fog itself differs... :/
 Feature Detection - How To Really Do It
#990 posted by LordHavoc [50.193.192.106] on 2013/03/09 13:32:03
The pr_checkextension cvar only indicates that the checkextension builtin (#99) is available, which then lets you query engine capabilities.
pr_checkextension exists in TomazQuake, DarkPlaces, FTEQW, I think FitzQuake, and I'd bet a few others too.
What I recommend adding this to defs.qc at the end:
float ext_dp_gfx_fog;
void() InitExtensions =
{
if (!cvar("pr_checkextension"))
return;
ext_dp_gfx_fog= checkextension("DP_GFX_FOG");
};
Then add this to the top of worldspawn():
InitExtensions();
Now you can check the ext_dp_gfx_fog variable at any time to see if the DP_GFX_FOG extension is supported, which describes how that fog command behaves.
This is not a general catch-all way to detect DP however as any engine can implement that extension, there is not any special way to detect a particular engine (nor any plans for one).
 @LordHavoc
#991 posted by sock [186.124.37.216] on 2013/03/11 01:03:10
Awesome, thanks for the extra information. I only plan to check for the basic DP engine from your site, I am not interested in supporting any other version.
I plan to use the following QC:
(in defs.qc)
float dpactive;
float dpextrafog;
float(string s) checkextension = #99;
(world.qc, function - worldspawn)
dpactive = cvar( "pr_checkextension" );
if (dpactive) dpextrafog = checkextension( "DP_GFX_FOG" );
 Standards
#992 posted by [78.37.171.41] on 2013/03/11 14:28:50
Several attempts to agree on anything failed. You could probably still find threads from like 15 and 10 years ago...
 Engines
#993 posted by LordHavoc [50.193.192.106] on 2013/03/12 06:26:21
The other engines I listed are *not* darkplaces, they are completely unrelated popular engines written by Tomaz (TomazQuake), Spoike (FTEQW), metlslime (FitzQuake), and so on.
They support the same extension mechanism to detect capabilities, they offer different sets of capabilities but with significant overlap.
Again this is not detecting an engine, this is detecting a capability, it just happens that DP_GFX_FOG is supported only by darkplaces currently.
I checked TomazQuake 1.481, Fitzquake 0.85, and FTEQW svn 4255 (current as of this moment) and it is possible for other engines to add support for this same extension depending on the whims of their maintainers, but currently only DarkPlaces offers this extension, it was added back in 2001-04-05, been there a long long time.
#994 posted by sock [186.124.37.216] on 2013/03/12 13:24:46
I know about the other engines (Fitz/FTE) my problem was with DP because of the fog parameters being different. I thought if I made my MOD work with Fitz it would work with anything, but it seems DP has gone in a different direction, hence the QC hack for engine detection.
#995 posted by necros [142.245.59.17] on 2013/03/12 13:39:32
feature detection only works if the features behave identically in each engine. since they do not, there should be a way to identify engines instead.
 Just A Note...
#996 posted by metlslime [159.153.4.50] on 2013/03/12 20:16:35
fitzquake does not actually support the quakec extension system. I support some extensions (e.g. worldspawn fog, worldspawn sky, entity alpha), but there's no quakec mechanism to detect them.
Most of the features I added in fitzquake are mapper-centric rather than modder-centric, which is why the extension system is missing (maps can't check it anyway, they can just add keys to entities or worldspawn and hope for the best.)
#997 posted by gb [46.142.47.255] on 2013/03/13 06:56:14
quite some maps do come with, or require, mods, though. The line is quite blurred tbh.
 Walking On Walls
#998 posted by Shamblernaut [203.161.90.29] on 2013/03/28 08:44:47
Hey guys,
Are you aware if there are any (engine or quakec) mods out there that allow the player to walk on walls / ceiling?
I'm interested as I'm thinking that MC Escher-esque architecture would be fun to map.
-Ben
#999 posted by Spirit [80.171.51.21] on 2013/03/28 09:29:59
FTEQW supports that with some cvar but don't ask me which one.
There is also a map by Markus Klar I believe.
 Blog Post 1000
#1000 posted by Preach [77.98.165.95] on 2013/03/28 12:32:38
(It's really just coding post 1000, it just feels like it ok...)
New post on the blog, laying the groundwork for a series on displaying text in exciting ways. This one doesn't break any new ground, it just describes the way to display text by sending it character by character. There is some more exciting stuff in the pipeline though.
http://tomeofpreach.wordpress.com/2013/03/28/text-manipulation-in-quake-i-the-basics/
Comments, questions or solutions to the "homework" all welcome. Also is there an up-to-date mirror of the ai cafe site I can link to in the post?
#1001 posted by Spirit [80.171.51.21] on 2013/03/28 13:35:24
 Spirit:
#1002 posted by metlslime [159.153.4.50] on 2013/03/28 20:33:43
you're probably thinking of that map "The Fly" by Markus Klar.
 Cool Map
#1003 posted by rj [82.9.177.217] on 2013/03/28 20:57:37
doesn't nearly get mentioned enough
 Cheers Spirit
#1004 posted by Preach [77.98.165.95] on 2013/03/29 16:22:36
Here's a second part hot on the heels of the first.
http://tomeofpreach.wordpress.com/2013/03/29/text-manipulation-in-quake-part-ii-inversion-of-control
This time we've got the exciting idea which gets around the lack of arrays in quake. We don't actually use it to do anything interesting yet...I promise that by part III the example code will produce something cool to look at.
 And Part III
#1005 posted by Preach [86.128.104.128] on 2013/03/31 01:12:56
Here we actually get to the good stuff - how to make text appear like a split-flap board. Just need the sound effect...
http://tomeofpreach.wordpress.com/2013/03/30/text-manipulation-in-quake-part-iii-parameters/
Hopefully the potential of the system shows at this point. I remember seeing how great the end screen for Qonquer was. My hope is by the end something like a menu drawn with a border which animates to open and close is made easy.
#1006 posted by Shamblernaut [203.161.90.29] on 2013/04/01 17:24:42
I just played the fly :)
it was a fun map...
I couldn't find any cvar except for wall jumping in FTEQW :(
 Preach
#1007 posted by necros [99.227.223.212] on 2013/04/03 03:54:53
just had the chance to read some of your text manip articles, very awesome. I've known about this method for a while since you originally brought it up but this lays it out really well. Thanks!
 Cheers Necros
#1008 posted by Preach [77.98.165.95] on 2013/04/04 00:44:21
I've got loads more ideas lined up (eventually the print functions should be able to draw a box round arbitrary scrollable text) but now I'm back to work posts will be more spaced out. Part IV should be out by the end of the week, it's about creating persistent state.
Credit where it's due: I first saw this idea in Pyrdon Gate by Frikac, which needed lots of menus and dynamic text, and did it like
textout('h', 'a', 'l', 'b', 'e', 'r', 'd', 0);
There was also a phase of creating text based games-within-games in quake mods, like Tetris and Snake. So using WriteByte to build centerprints is not original with me. The function-as-iterator and the dynamic print functions are new ideas though, and I'm pretty excited about them (as you might have guessed!)
 Ceiling Running
#1009 posted by Spike [86.182.96.71] on 2013/04/05 23:26:05
fte features:
give self.gravitydir_z=1 (-1 or 0 to revert)
gravity will now point upwards.
give self.movetype=31 (3 to revert)
gravity will change based upon the angle of the surface below you. you can run up walls by just facing upwards and walking forwards.
they're intended to be used explicitly by mods, but you can force things with the 'give' command, and its ability in fte to poke various qc fields, but note that it only really works in single player.
The current SVN build will rotate the view along with gravity but slightly older ones won't, and this will be needed if you want to run on ceilings properly.
 Double Damage
#1010 posted by Preach [77.98.165.95] on 2013/04/06 02:33:41
Didn't Matrix Quake have wall-walking of some description? I'm sure that was why it needed a custom engine...
While I'm posting something almost helpful I might as well link to the next Text post.
http://tomeofpreach.wordpress.com/2013/04/06/text-manipulation-in-quake-part-iv-state/
I swear the next post does all the remaining heavy lifting, and the rest will just be 100 fun things to do with text on a screen.
#1011 posted by NotoriousRay [74.107.82.97] on 2013/04/07 18:24:28
Have there been any attempts to make a more modular/extensible qc engine? Like extending a known mod's (compiled) progs.dat with some of your own stuff (for mappers, mostly new point entities or monsters)? Is it even feasible?
#1012 posted by necros [99.227.223.212] on 2013/04/07 20:37:55
like modifying an existing mod?
or allowing modification of existing progs without source through the engine?
#1013 posted by necros [99.227.223.212] on 2013/04/07 20:39:36
Actually, that wouldn't be so bad. It would be cool if a compiler was integrated into the engine so you would just distribute qc files and when the engine starts it would compile it on the fly similar to Doom3/Quake4.
#1014 posted by NotoriousRay [74.107.82.97] on 2013/04/07 21:03:02
Yeah, without modifying the existing progs.
#1015 posted by necros [99.227.223.212] on 2013/04/09 00:54:37
same as with the mapping help thread, should a link to the wiki or the coding section of the wiki be added to the start of this thread?
 Aaafter Ten Thousand Years...
#1016 posted by Preach [77.98.165.95] on 2013/04/27 15:44:37
Yeah, you've had enough of a rest now, time for more blogging!
http://tomeofpreach.wordpress.com/2013/04/27/text-manipulation-in-quake-part-v-coroutines/
This is the last of the heavy-lifting, high-concept bit of messing around with text in quake articles. At the end of this one all the messy stuff to do with printing text is moved into the helper functions we've defined, and code that wants to print text looks uncluttered and simple.
Future articles will just be cool things you can do with this, like how to combine this printing with conventional strings, how to compare streamed text with a quake string, printing floats to the screen, automatically creating boxes for variable text. It's gonna be fun...
 Path_corner Enemies
#1017 posted by ijed [200.73.66.2] on 2013/05/09 00:11:55
How can I get my enemies to do nothing on reaching the last path_corner?
Right now they begin walking towards the player (notarget or not) after ending the path.
I know I can just clean movetogoal or force idle instead of walk, but I'm pretty sure this has been fixed in other code bases, and by map hackery.
I've tried various ways of ending the path in editor, and nothing seems to work.
 Relevant Code
#1018 posted by Preach [77.98.165.95] on 2013/05/09 01:04:01
self.goalentity = self.movetarget = find (world, targetname,
other.target);
self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
if (!self.movetarget)
{
self.pausetime = time + 999999;
self.th_stand ();
return;
}
So to get to the bit which makes the monster stop we need the find call to return world. The obvious move of not setting a target on the waypoint fails, because it's almost certain that the player's targetname is also "" (the empty string). This is why the monster instead starts walking towards the player.
So how can we make sure that find returns world instead? Well, find returns world if nothing matches. So what we do is choose a target is not equal to any targetname on the map, like "this is a made up targetname which nobody in their right mind would use".
Alternatively use Quoth and "wait" "-1".
I have to admit that before the post I had an misapprehension about find. I thought that the function looped around, so when it reached the last entity it would wrap around to world and back until it reached the start entity again. It doesn't do this - once it reach the end of the entity list it just stops and returns world.
 Interesting
#1019 posted by ijed [200.73.66.2] on 2013/05/09 01:40:47
Thanks.
Does the player not having a null string targetname affect anything else like this?
 Don't Think So
#1020 posted by Preach [77.98.165.95] on 2013/05/09 02:06:15
There's a single central function which handles how all entities get triggered - and that has a check for an empty target before it runs. The trigger_teleport_touch function also searches for a target, but the trigger_teleport spawn function throws an error if target is not set. Note that you could use a map-hack to get around the latter check, but it's a fairly useless effect.
#1021 posted by necros [99.227.215.224] on 2013/05/09 16:53:48
The obvious move of not setting a target on the waypoint fails, because it's almost certain that the player's targetname is also "" (the empty string).
...oh my god... all these years, I just assumed that that functionality was broken! that's why I added the wait -1 into quoth! I never saw the correlation between find matching an empty string.
I have to admit that before the post I had an misapprehension about find. I thought that the function looped around, so when it reached the last entity it would wrap around to world and back until it reached the start entity again. It doesn't do this - once it reach the end of the entity list it just stops and returns world.
This is also important to remember if you are using find when starting in the middle of the list. You need to remember to loop back around to the start of the list to cover all the entities you've missed by starting in the middle.
 Blogosphere Time
#1022 posted by Preach [77.98.165.95] on 2013/05/10 21:59:05
So a new article for the blog, this time dealing with map hacks. I look at why one dodgy-looking part of a common map-hack technique is actually not so dodgy. It's also a chance to look at how floating point works. It's deceptively titled "Infinite ammo"
http://tomeofpreach.wordpress.com/2013/05/10/infinite-ammo/
For some more interesting reading on the issues of floating point maths I recommend Raymond Chan's recent post http://blogs.msdn.com/b/oldnewthing/archive/2013/05/08/10416823.aspx
 Demo Parsing Code
#1023 posted by Mandel [80.217.79.210] on 2013/05/17 20:45:49
For what it's worth, I've published my demo parsing code (a c library) at github:
git clone http://github.com/mandelmassa/libdemo
Libdemo passes my test suite on x86 win32 and linux, arm, and mips, so it's theoretically endian safe. It should support standard and Fitzquake protocols but there has been minimal testing on fitz. I will accept patches but I'm new to github so I don't know for sure how it works. License is MIT - basically, do what you want with the code. I hope someone finds it useful.
The purpose of the code is to read a Quake .dem file from your file system into a linked list in memory. You can edit the linked list as you wish, and then use functions in the library to write the demo data to a file.
I've used older versions of this code to write numerous tools for Quake demo editing, mainly for QdQ movies.
 Nextthink Time
#1024 posted by Qmaster [50.40.240.99] on 2013/05/21 22:09:35
Can I give nextthink a value of (time + FALSE); ?
#1025 posted by necros [99.227.215.224] on 2013/05/21 22:46:34
in qc (and c), 0 is false and all other numbers are true, so time + FALSE just means time + 0 or just time.
You can do this and it means that the think function will run on the very next frame.
 Nextthink
#1026 posted by Preach [77.98.165.95] on 2013/05/21 22:54:43
On a normal entity you can do that, and even stuff like nextthink = 0.05 works as well. As long as nextthink is positive and before the server time + the current frame length, the function runs.
But since this comes after your posts about func_train, I'm guessing you want to do this on a MOVETYPE_PUSH/SOLID_BSP entity. The rules are much more complicated for them, you can read some of the detail from earlier in the thread:
http://celephais.net/board/view_thread.php?id=60097&start=325&end=354
The most important thing is to always do self.think = self.ltime + delta, never compare to time directly, or you won't get the correct behaviour when your entity is blocked. delta must be strictly greater than zero, or the think function won't run.
If you need reliable, frame by frame functions to run on your MOVETYPE_PUSH entities, I'd recommend adding a function to startframe which finds all the relevant entities by classname and run your function on them there. You get the added bonus of getting to run the "think" function before they get physics run this frame.
#1027 posted by necros [99.227.215.224] on 2013/05/21 23:36:09
oh whoops, I missed that it was for a bsp entity.
 Well, I'm Guessing
#1028 posted by Preach [77.98.165.95] on 2013/05/22 00:18:45
Because who would think to qualify their question like that, unless they already knew?
What it has reminded me is that I must find that old article I wrote about making smoothly-moving pusher entities, rewrite the bits that were hard to follow, and post it to the new blog. That and maybe some posts which condense all that info linked about about what physics happen when and why...it's all a bit random, needs a bit of a hook to hang it from.
 Trying To Make A Perfectly Smooth Custom Func_train
#1029 posted by Qmaster [50.40.234.181] on 2013/05/22 05:31:16
No matter what I set delta to when I add it to ltime, it always stops for 0.100 secs at path corners. I've created all new functions just for my train entity so I can isolate what is going on.
I have only changed names and ltime increment values from 0.100 to 0.0001 (overkill precision for 1500fps (1/1500). 1500fps is the highest I've seen in Darpkplaces with my nose to the wall ;) ). I'm trying to get it to just go straight to the next frame without pausing.
In my SUB_CalcMove replacement there is a line:
self.nextthink = (self.ltime + traveltime);
This is the same as in subs.qc. Is this the culprit?
 Oh And Also
#1030 posted by Qmaster [50.40.234.181] on 2013/05/22 05:33:20
I don't care about physics or player blocking. These trains are part of the environment and can be SOLID_NOT if that helps (crazy stuff if I just change it to SOLID_NOT though :D ).
 Quick Check
#1031 posted by Preach [77.98.165.95] on 2013/05/22 09:36:04
Have you removed the following
if (traveltime < 0.1)
{
self.velocity = '0 0 0';
self.nextthink = self.ltime + 0.1;
return;
}
That sets 0.1 seconds as the minimum travel time.
Also yes, do change your entity to non solid with MOVETYPE_NOCLIP and you will have a much easier time. SOLID_BSP entities are hard!
Finally, you may not need to set think functions at all if you want an instant reaction. Why not just run the function directly?
 Technoplats.qc - Not Sure What's Wrong
#1032 posted by Qmaster [50.40.234.181] on 2013/05/22 15:18:56
//Func_train Alternate: Goal is to have no 0.100sec
//stops at path_corners (unless wait is set)
//=================================================
//by Qmaster for techno mod, specific for my base map
//Current issues:
//Train flickers back and forth along path.
// Apparently the train is moving along the path
// at the speed of frame instead of time
//Predecs
//-------
void () traintech_next;
void () traintech_find;
void () traintech_move_done;
//My version of SUB_CalcMove (see subs.qc line 142)
//-------------------------------------------------
void (vector tdest, float tspeed, void() func) techtrain_move = {
local vector vdestdelta;
local float len;
local float traveltime;
self.think1 = func;
self.finaldest = tdest;
self.think = traintech_move_done;
//Does self.origin ever reach tdest? Should I do something like len below
// and do "if ( (len < 0.001) )" for this if statment to work?
if ( (tdest == self.origin) ) {
traintech_move_done();
}
vdestdelta = (tdest - self.origin); //get vector dist to target
len = vlen (vdestdelta); //floatify distance to target
traveltime = (len / tspeed);
self.nextthink = (time + traveltime);
self.velocity = (vdestdelta * (TRUE / traveltime));
};
//My version of SUB_CalcMoveDone (see subs.qc, line 178)
//------------------------------------------------------
void () traintech_move_done = {
setorigin (self,self.finaldest);
self.velocity = VEC_ORIGIN;
self.nextthink = CONTENT_EMPTY;
if ( self.think1 ) {
self.think1 ();
}
};
//Targetname is set
//-----------------
void () traintech_use = {
if ( (self.think != traintech_find) ) {
return ;
}
traintech_next ();
};
//Path_corner has wait set, so wait
//---------------------------------
void () traintech_wait = {
if ( self.wait ) {
self.nextthink = (time + self.wait);
sound (self,CHAN_VOICE,self.noise,TRUE,ATTN_NORM);
} else {
train_next();
}
};
//Find next path_corner from self.target
//--------------------------------------
void () traintech_next = {
local entity targ;
targ = find (world,targetname,self.target);
self.target = targ.target;
if ( targ.speed ) {
self.speed = targ.speed;
}
if ( !self.target ) {
objerror ("traintech_next: no next target");
}
if ( targ.wait ) {
self.wait = targ.wait;
} else {
self.wait = FALSE;
}
sound (self,CHAN_VOICE,self.noise1,TRUE,ATTN_NORM);
techtrain_move ((targ.origin - self.mins),self.speed,train_wait);
};
//Find inital path_corner from self.target and setorigin to it
//--------------------------------------
void () traintech_find = {
local entity targ;
targ = find (world,targetname,self.target);
self.target = targ.target;
setorigin (self,(targ.origin - self.mins));
if ( !self.targetname ) {
self.nextthink = (time + 0.100);
self.think = traintech_next;
}
};
//The train entity
//-----------------
void () func_traintech = {
if ( !self.speed ) {
self.speed = 24.000;
}
if ( !self.target ) {
objerror ("func_traintech without a target");
}
if ( !self.noise ) {
self.noise = "misc/null.wav";
precache_sound ("misc/null.wav");
}
if ( !self.noise1 ) {
self.noise1 = "misc/null.wav";
precache_sound ("misc/null.wav");
}
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NOCLIP;
self.use = traintech_use;
self.classname = "train"; //I hope this doesn't set anything engine-side
setmodel (self,self.model);
setsize (self,self.mins,self.maxs);
setorigin (self,self.origin);
self.think = traintech_find; //Needed for use function
traintech_find();
};
 Umm...
#1033 posted by Qmaster [50.40.244.117] on 2013/05/22 22:02:13
you can ignore that previous post. I'm implementing Custents trains (with tweaks of my own haha)
 Text...or Should I Say Numbers
#1034 posted by Preach [77.98.165.95] on 2013/06/05 02:17:02
So BSP things take a back seat to another Text article:
http://tomeofpreach.wordpress.com/2013/06/05/text-manipulation-in-quake-part-vi-numbers/
Today we take a look at printing out numbers, one of those things you just take for granted in normal string code. But it's really important if you're going to use this to display, say, a custom scorecard like Qonquer did using screen prints.
I actually tore through making this one, because I was excited about an esoteric application of it - creating strings like "*21" or "*87" with any number, using the text streaming. It turns out that the loopholes for turning text streams back into normal QC strings are smaller than I imagined - just a bit too hacky. So that got cut for now, but I've not totally give up hope of making it useful.
#1035 posted by necros [99.227.215.224] on 2013/06/05 04:40:45
just took a quick scan over the article... the expanding code box doesn't seem to work for me. it expands, but it's all on a single line (the <br /> tags are visible).
 Grr, Wordpress
#1036 posted by Preach [77.98.165.95] on 2013/06/05 11:55:01
That was working a few days ago, and then the gremlins messed with it...fixed!
 Setsize With Respect To Other Vectors
#1037 posted by Teknoskillz [75.68.212.63] on 2013/06/16 20:08:23
HI:
I know the only 3 valid sizes are point, shambler and player, but I am just experimenting with the superspike model, attempting to have it do things like ricochet off bsp's for example, and one problem was it was not pointing in the new direction after rebounding, but I found vectoangles of the velocity ought to fix it? However I was wondering how could we use that to look at the spikes angles, and do a setsize that takes us out of the models default point size, and give it a better bounding box, that is more shaped to the model? I did some rudimentary tests, and found that:
setsize (self, '1 -0.5 -0.5', '8 0.5 0.5');
(self being the spike)
Works , except if its first angle coordinate, which I am guessing is its yaw? ,Is the larger value of the 2? Im just curious if anyone here can see a formula where we could resize the bounding box depending on its angles , or maybe the velocity, so that its always covering the spike....?
 QuakeC To Fix Model Wiggles?
#1038 posted by Jare [75.140.104.96] on 2013/07/09 13:37:11
Can I use quakeC to get rid of the wiggly darkplaces models in my game? Or do I need to switch from .mdl to .mdl3? (or whayever the extension was, just a guess my friend made)
Very curious, maybe it's something completely diffrrent.
 Typically
#1039 posted by ijed [200.73.66.2] on 2013/07/09 16:46:46
It's best to use the LG on the Wiggles; they're a tough enemy and their armor wedgie ability can catch you out when you're least expecting it.
...
Give us more info on the problem you're having :)
#1040 posted by necros [99.227.215.224] on 2013/07/09 21:44:55
i think he's talking about vertex dancing.
in which case, yes, the only solution is to use a different model format. md3 will solve nearly all your problems.
 Vertex Dancing
#1041 posted by jare [75.140.104.96] on 2013/07/09 22:33:27
@ijed haha necros summed it up
@necros thanks for the info!
 Heh
#1042 posted by ijed [186.79.235.165] on 2013/07/10 03:01:59
.iqm is a good format as well and also supported by dark places as well.
 Ijed
#1043 posted by Jare [75.140.104.96] on 2013/07/10 04:20:55
Oh thanks :P
#1044 posted by necros [99.227.215.224] on 2013/07/10 21:19:42
Sorry, I always forget that one since I've never used it, but I believe it might be better to do IQM because it is supported and actively being maintained in blender plugins...
I think it has skeletal animation as well?
 Yep
#1045 posted by ijed [200.73.66.2] on 2013/07/10 22:24:18
 LTIME PAINS
#1046 posted by Qmaster [50.40.207.219] on 2013/08/01 01:21:42
How is ltime calculated? In otherwords, why would this code have two separate entities start their movement at different times? It's starting essentially func_trains (they're not really but they are MOVETYPE_PUSH and move the same way)
local float eltime;
eltime = self.ltime; //force ltime to be the same?
stemp = self;
self = self.target1;
self.ltime = eltime;
self.think = qtrain_start;
self.nextthink = (self.ltime + 0.100);
self = stemp;
stemp = self;
self = self.target2;
self.ltime = eltime;
self.think = qtrain_start;
self.nextthink = (self.ltime + 0.100);
self = stemp;
...
...
...
I have already tried the servertime trick with StartFrame, but they still start at different times. Apparently they aren't starting on the same frame??!?
 Ltime
#1047 posted by Spike [86.139.73.55] on 2013/08/01 01:40:17
ltime is incremented for the number of seconds the door or whatever has been moving for. If the door is blocked for whatever reason, ltime will not change and the door will freeze in place.
this ensures that the think is scheduled for when it arrives at its destination rather than in true seconds.
the whole point about ltime is that its local to the entity in question, and is allowed to freeze as required. If you want your trains to work as a pair, you'll need to ensure that if one is blocked, the other also stops moving, and take extra care to re-sync them when they start moving again.
seriously, why has noone made a map where you have to lure monsters to a certain area to block a train to desync them so you can jump from one moving platform to another? :s
 Spike Is A Genious
#1048 posted by Qmaster [50.40.207.219] on 2013/08/01 01:55:02
That's a cool idea! Secret area maybe?
Okay. So bprint debugging has confirmed that the nextthink's are infact the same for both entities. Does this mean that they will start at the same time though? Obviously no. Still no cookies.
So I'll step it through. Preach? Correct me if I'm wrong anyone.
Function sets think for two entities regardless of targetname (entities are stored as entities not targetname, target1 and target2 are .entities)
Function sets nextthink for two entities
Nextthinks are confirmed the same, bprint to console so I know.
Entities are set to start in nextthink seconds
This frame just set the nextthink time, so these entities will get called in the same frame in ltime+x. Well, theoretically they would. What's the tolerance for time when attempting to get two entities to start on the same frame in x seconds? + or - 1 frame? 10 frames?
These entities are not moving so ltime is not increased.
They never start then theoretically. But they start anyway just to confuse me.
1st one starts after about 2.5 secs
2nd one starts after about 4 secs
So how is ltime incremented while an object like a door is NOT moving????
 Potential Reason
#1049 posted by Preach [77.98.165.95] on 2013/08/01 02:05:18
Remember that the quake engine loops through entities and applies physics to them in a sequence. It can't process them "simultaneously". Imagine that we've already run physics on target1 this frame, but that we haven't run physics on target2. If we run your function at that moment, the two will be synced when the function ends, but by the end of the frame we'll have run an extra tick of physics on target2, desynchronising them again. Could that be what's occuring?
#1050 posted by necros [99.227.215.224] on 2013/08/01 05:23:59
a bmodel entity must have it's nextthing greater than ltime or it will not move.
#1051 posted by Spike [86.173.174.57] on 2013/08/01 05:40:50
its a bit clumsy, as it tries to get the maths precise so that the train stops exactly where it needs to be even if its only a fraction of a frame away.
the ramifications of this is that ltime does not increase if self.ltime>=self.nextthink.
thus if you want a bsp object to move or spin, it MUST have a valid nextthink set.
remember that the timings are precise in that the movement covers the correct distance, rather than it arrives at the projected time. this isn't some national railway with precise time keeping. Its just trying to avoid moving through walls if you've got a low framerate.
If you have some third entity clearing everything out but the velocity, one pusher can still get blocked and ltime will not update while the other starts moving around freely.
An entire second and a half in 4 is too high for any precision issues. Are you sure its not getting blocked or anything? You're sure that you're using .ltime and not time when setting nextthink, etc?
 FIXED!!
#1052 posted by Qmaster [50.40.207.219] on 2013/08/01 06:22:56
Turns out I had forgotten to recompile with ltime and it was still using time. However, even though with ltime it was reealllly close, I still had a discrepancy of about 0.8 to 1 game unit when the two entities started from the same point.
-Edit!-
------------------
I FIGURED IT OUT!!!!!!!
There is a latency, a lag, within a frame from one object to another when the physics are calculated. The two entities had been created several dozen entities apart in the map (about 15 min of mapping on another part of the map while I was thinking about what to do). This means that several dozen entities needed to be ran before the other entity would run, causing enough time lag for a small gap in start times.
The fix?
Duplicated lagging entity. Deleted original. Placed duplicate entity back in the same spot.
Done.
And that only took me 2 months to figure out.
Wait till you see what I use it for in my new map!
 Fish!
#1053 posted by ijed [200.73.66.2] on 2013/08/06 22:56:01
An obscure bug with the monster that nobody cares about.
Basically, they don't move when scraping their heads against the top of the water volume they're in.
Anyone have a fix for this? I can trade you a fish model with a normal sized head when it dies...
#1054 posted by necros [99.227.215.224] on 2013/08/06 23:05:52
A simple way is to use pointcontents to check a point above the fish's head and if it is out of the water, reset the monster's z origin to the previous frame so that it can still move horizotally, but won't move upwards into a position where it will be stuck.
This has the small chance of making a fish get stuck in a wall, but you'd have to make a very specific shape of wall and water edge for it to happen.
 Bait On A Hook
#1055 posted by Preach [77.98.165.95] on 2013/08/06 23:29:12
Banging their heads on the surface usually occurs when they're trying to swim up to the level of an .enemy who's higher up than them. You can create a dummy entity called worm. When you want a fish to swim, stash their proper enemy in a temporary variable, and set their .enemy variable to the worm. You can then position the worm to lead them where you want - place it in the direction of the real enemy, but at an appropriate height vertically. Remember to reset .enemy once you've called the ai movement functions.
 Aha
#1056 posted by ijed [200.73.66.2] on 2013/08/07 00:23:49
The issue was obvious really - like what happens to a scrag when it hits ceiling and you're above it.
Thanks guys.
 Doing Things The Bad Way
#1057 posted by Preach [77.98.165.95] on 2013/08/07 00:32:00
The above post is the good way to do things. But we don't like the proper way of doing things, we want to save an entity! The bad way to do things is to instead stash the old height of the fish's enemy, move THE REAL ENEMY down, then instantly restore that enemy's position when the movement function is done. If you're breaking the rules, you should go all the way and skip the call to setorigin - that would only cause actual collsions to occur when you want to avoid that happening. God help you if the fish collides with the enemy though...
 Field Pointers
#1058 posted by Preach [77.98.165.95] on 2013/08/07 12:23:38
New QC article today - on field pointers. There are two - yes TWO - reasons to read today's article! One is if you'd like to learn what a field pointer is in QC and how to use them. They help you write generic code.
Even if you don't care about the technical knowledge, the article solves a practical problem: how do you code an entity which has templates? Templates here are where a mapper can set a single value on your entity and get a bunch of default values applied, and the mapper can selectively override these defaults.
http://tomeofpreach.wordpress.com/2013/08/07/field-pointers-in-qc/
#1059 posted by sock [186.108.74.88] on 2013/08/07 12:48:53
As always a good read and I learned something new about function parameters. :)
I’m going to share a snippit of code from Quoth
You should one day publish that code, I imagine it would be awesome see how you organize and structure stuff. I would love to see how you implement features.
 Gleaming Spires
#1060 posted by Preach [77.98.165.95] on 2013/08/07 19:37:28
Don't be daft, I'm showing off the good bits! The rest of it is all cludged together. Bit by bit I'll try to blog the how-to behind all the good bits, so that everyone can make a mod better than Quoth.
#1061 posted by necros [99.227.215.224] on 2013/08/07 20:14:07
Don't be daft... all the bad bits are me. :P
 Almost Forgot
#1062 posted by ijed [200.73.66.2] on 2013/08/07 22:49:47
Here's the fixed death frame fish model:
https://www.dropbox.com/s/eluwi8hwa9ot0yd/fixed_fish.7z
It's also got some 'small' frames, if anyone wanted to make, say, a school of piranha.
#1063 posted by necros [99.227.215.224] on 2013/08/07 23:16:46
oh btw, that's a great post about the field-as-arguments.
 Nonsense Necros...
#1064 posted by Preach [77.98.165.95] on 2013/08/07 23:52:59
I was considering posting an awful bit of Quoth code for the sake of comparison - and the function that sprang to mind immediately was the coop removal function, which I wrote entirely myself!
 More Field Pointers
#1065 posted by Preach [77.98.165.95] on 2013/08/09 15:23:51
So here's a more thoughtful counterpoint to the lovely beautiful code stuff above. It's a second blog post about field pointers on the surface, but it's also about the battle writing clean code and battling the technical limits. There's also an exciting cliffhanger for part III...
http://tomeofpreach.wordpress.com/2013/08/09/going-overboard-with-field-pointers/
Since this is really a mapping forum, I'll give you guys the cuttings about how this stuff relates to maps. Yes, it is possible to overflow the stack if your triggers get too complicated, even in stock Quake. You're probably doing some serious neg!ke style map hacks if you get to that point. There's a workaround if you ever do hit the limits though: give one of your triggers a delay. The stack will be reset between the triggers which precede and follow the delayed trigger. You can think of this like giving the engine a chance to catch its breath!
 Revenge Of The Field Pointers
#1066 posted by Preach [77.98.165.95] on 2013/08/23 15:25:56
http://tomeofpreach.wordpress.com/2013/08/23/getting-even-with-field-pointers/
Here's an article with two ways of fixing the problems from last time - using macros and using arrays.
I was going to go further, try and create a system where you could have an arbitrarily long chain of entities using each other without overflowing the stack. The plan was to split SUB_UseTargets in two, the first half would make a global linked list of targetted entities, and the second half would work through this list and call their use functions. If one of these use functions called SUB_UseTargets recursively, it would add the entities to the global list but then return, and let the original invocation call the use functions.
There are two problems with the plan though. One is that the order of which use functions start and complete has been changed by this transformation, which could break maps in some unanticipated way. The bigger problem can be found in this discussion:
http://www.celephais.net/board/view_thread.php?id=4&start=13098&end=13108
It's possible, if maybe unlikely, for an entity to legitimately be triggered recursively. This doesn't work well with the linked list. There might be ways to fix this, possibly by letting the function recurse in these places, but I'll have to give it some more thought.
 Chainlist = Findradius(origin,radius)
#1067 posted by sock [181.1.238.75] on 2013/09/04 19:14:28
It is the subtle things in life that cause the most problems ...
The findradius QC command can work differently in Darkplaces compared to Fitz engines. It may not seem like much of a difference but it can cause serious problem if you are not aware of it.
The Fitz engine ignores all entities with .solid=SOLID_NOT when creating a chain list for the findradius command. This is a good thing because certain types of entities (particles, delay spawns) can be excluded from this function easily and included when needed.
Darkplaces (older versions) does not seem to have any exceptions, it will gladly find ANY entity within range and create a chain list. The problem is the findradius command will freely 'corrupt' the chain field and if you use it for anything else then those lists will start to fall apart.
I recently switched over to a chain list for my particle system because it was crazy to keep creating/deleting them all the time. So I cycle round a chain list and it works fine in Fitz. In Darkplaces the lists were getting corrupted and I did not know why and then I finally found the problem, Findradius was finding the particles (my system can use sprites or models) and changing the chain field.
It seems Preach has run into this problem (post#962) but I could not find any other forum links. Apparently there is a sv_gameplayfix_blowupfallenzombies to fix this but the naming of it is not easily recognizable as something to do with the findradius command.
I tried to find a way for Darkplaces to exclude entities from the Findradius command. I set the model field to an empty string or "null" (dp documentation) and setting the bbox and size to zero, but nothing seems to make a difference.
I assume the latest version of Darkplaces fixes this by disabling the fallenzombie gamefix, but not everyone using DP updates all the time. It certainly easy to code for this change, but it is frustrating to find out about this the hard way.
 Compatibility Battles
#1068 posted by Preach [77.98.165.95] on 2013/09/04 20:20:04
Yeah, the more experimental engines are a bit more of a hassle to keep combatible with. Perhaps we should try and create a little community config file which restores darkplaces etc. to standard quake compatibility. Then add it to quake.rc to execute between config.cfg and autoexec.cfg. Incidentally that's the best time to aply strongly recommended cvar defaults - it replaces whatever was autosaved in the config last time, but lets people who think they know what they're doing override them in the autoexec file.
In your specific predicament, I'd recommend creating an extra entity field, perhaps:
.entity p_chain;
...and use that to replace your code's use of chain.
 Could Also Contact LordHavoc
#1069 posted by ijed [200.73.66.2] on 2013/09/04 21:33:11
He's usually on the ball with these types of fixes and happy to help out.
#1070 posted by Spike [86.143.205.227] on 2013/09/05 04:20:06
sv_gameplayfix_blowupfallenzombies defaults to 0 in current builds (along with other such gamecode-changing settings), but the old value might linger via configs. Probably the easiest thing to do is to detect dp at load time somehow (to avoid warning messages in other engines) and just cvar_set it to 0.
(use solid_corpse instead of solid_not if you want to be able to shoot/find zombies, I guess)
but yeah, its probably better to simply use some other field like .enemy or .owner instead of .chain
 Blogging Back
#1071 posted by Preach [77.98.165.95] on 2013/09/06 00:42:26
So I took the idea I posted above, along with some other thoughts which have been coagulating for the past few months, and made a blog post. It's all about the engine config system, written mostly for someone who's writing a mod and wants to know what to do - and not do!
http://tomeofpreach.wordpress.com/2013/09/05/quake-rc-and-being-a-good-citizen/
There's a nice bit of copy-paste code at the bottom for controlling darkplaces cvars, although it covers both the opting-out and opting-in cases so users may need to tweak it slightly to suit their needs.
 Locals Conflicting With Func Args?
#1072 posted by jt_ [68.42.82.10] on 2013/09/08 19:18:32
Is it possible for a local to conflict with arguments to a function? I noticed that with a (clean) progs106, the SpawnMeatSpray function (maybe more) takes two vectors, org and vel; but in the function itself has a local named org. SpawnMeatSpray uses org only when calling setorigin and it seems to be using the argument org, not the local (assuming, can't check atm).
 Qc + Locals
#1073 posted by Spike [86.143.200.67] on 2013/09/08 19:45:16
arguments ARE locals.
dupe defs are ignored.
initialising a dupe is an error (vanilla qc initialisers make it a constant).
qc doesn't support scoped locals, other than to the function. unlike C+Java+etc, blocks don't have private locals, and locals are still valid beyond the end of the block that they were defined in.
 Thanks, Spike
#1074 posted by jt_ [68.42.82.10] on 2013/09/08 21:07:49
 Buzzsaws
#1075 posted by Qmaster [50.40.214.74] on 2013/09/14 06:00:34
Does anyone have usable buzzsaw code? For some reason the buzzsaw.qc file I have doesn't work and the saws don't match up with path_corner's. I've tried rewriting the code to use SUBCalcMove but it starts moving off at an angle instead of following a path, but the "original" I have cause it to jump around in my map. I've tried custents buzzsaw.qc but it does the same thing. It'll follow the paths in r2m7 but be offset vertically from the actual path locations and do a kind of jiggle up jump.
What am I missing?
 ...
#1076 posted by Qmaster [50.40.214.74] on 2013/09/14 06:32:53
Okay, I found the original doe_qc.zip source code online: http://www.gamers.org/pub/idgames2/more_idstuff/doe_qc.zip
Copied buzzsaw.qc into my code and ran it. Buzz saws still hovering about 16 units above the tracks they should be in the Last Bastion (r2m7). Found doe progs.dat (dated 2008 from when I copied it off the CD, verified the same size as in the pak0 under rogue directory) and it does the SAME THING!!
Is this Darkplaces only related?
 Okay Yep.
#1077 posted by Qmaster [50.40.214.74] on 2013/09/14 06:36:35
it's a darkplaces bug. Buzzsaws work fine in WINQUAKE.EXE. Is there a gameplay console var fix for this??
 Okay...
#1078 posted by Qmaster [50.40.214.74] on 2013/09/14 17:21:23
what's happening with the buzzsaws is that they behave like monsters. They change their movetarget when their bounding box touches a path_corner, not when their origin reaches the path_corner's origin. Now then...to figure out how to ignore path_corner.touch functions....
 Buzzsaws Solved!
#1079 posted by Qmaster [50.40.214.74] on 2013/09/14 18:24:27
No code modifications required.
Just positioned my buzzsaws outside of the tracks such that they have time to move and get inline with the path_corners. (had to bsp_to_map the r2m7 map and see what they did to make it work, the buzzsaws were about 64 units away in both x and y directions from their starting path_corner.) There are still a few glitches if the path_corner's are positioned a distance away from eachother that Quake doesn't like, or if the speed of the buzzsaw isn't just right. (10 usually works and is default)
 Sounds Good!
#1080 posted by ijed [87.86.255.130] on 2013/09/16 03:28:27
 Keeping Score
#1081 posted by mechtech [65.190.158.200] on 2013/09/30 02:10:22
Any mod out there that can count damage done in a level and give a total at intermission?
I think it would be fun. Make a replay of the original game interesting. Timing a quad damage would be very important I suspect.
 Stealth Damage
#1082 posted by sock [186.124.38.243] on 2013/09/30 02:13:11
I added damage done to my ITS mod, there is a stealth stats screen you can check at anytime during play of a map.
 Sock
#1083 posted by mechtech [65.190.158.200] on 2013/09/30 02:26:29
That's the idea. A mod that can take e1m1 and give a score at the end without modifying anything else. Vanilla Quake with a score card at the end. I'm sure it could get complex give points for health, armor and ammo and suck points off for total time.
#1084 posted by R00k [68.70.94.70] on 2013/10/01 21:30:43
I've added damage given, and damage taken to my multiplayer mods. It's not difficult at all.
I then get a survival skill score by this
score = damage_given / (damage_taken+damage_given)
:D
#1085 posted by Spirit [80.171.27.210] on 2013/10/01 23:28:25
I kinda hope that some day more engines will support sqlite and we could use that to track and record all kinds of things locally. FTEQW supports it.
#1086 posted by Spike [86.140.149.47] on 2013/10/03 18:03:05
sql is only really useful for single player, and even then you can often get away with frik_file instead.
when it comes to deathmatch you probably want some central server recording matches in aggregate, which would likely be programmed in something more php-ey instead of qc. naturally this avoids sql in the game server, but does require some sort of communication to said server...
 Extract Vertexes From .MAP/.BSP
#1087 posted by ALLCAPS [174.106.183.23] on 2013/10/03 21:30:38
Is there an easy way to heist the vertex/mesh data from a Quake map? I'm trying to whip up some C# for using Q1 brushwork inside of Unity3D, and I'm hitting a wall.
Since I don't care about the lightmaps or vis data, I figured I'd try to divine the vertex data from the .map, but converting from the brush based geometry (calculating planar convergence) is beyond my skill. It'll probably be easier to let a compiler do the lifting on that and just read the data I want out of the resulting .BSP Are there any libraries available for working with Q1 .BSP?
#1088 posted by metlslime [159.153.4.50] on 2013/10/03 21:33:54
i think the bsp is a better choice as it is more mesh-like, and is already cleaned of things like tjunctions, overlapping polygons, etc.
#1089 posted by Spirit [80.171.159.202] on 2013/10/03 21:47:23
#1090 posted by Preach [77.98.165.95] on 2013/10/03 22:27:07
when it comes to deathmatch you probably want some central server recording matches in aggregate, which would likely be programmed in something more php-ey instead of qc. naturally this avoids sql in the game server, but does require some sort of communication to said server...
The most obvious solution is to program the central server to mimic a client connection to the game server! Sure you waste a client slot on your stats bot, but who plays 16 player deathmatch anymore anyway...Of course you'd communicate directly from the QC using SVC messages to ensure your code runs on every engine. Just write, lets say byte-by-byte UTF8 encoded JSON, wrapped up as a sprint statement to the bot.
Preach goes off to write a web server in QC and is never heard from again
#1091 posted by necros [99.227.113.78] on 2013/10/04 02:05:31
my inner nerd has been awakened. this sounds like such a cool idea :D
#1092 posted by Spike [86.140.149.139] on 2013/10/04 02:17:16
@preach
I know you jest, but there are bots that connect to QuakeWorld servers to scrape scores already...
That said, QuakeWorld does at least support explicit spectators so you don't need qc code to make them non-solid to avoid interfering with the game with free frags.
@ALLCAPS
walk the surface list. each surface has a list of edge indicies (either positive or negative). each edge has two references to each vertex. if the edge index was positive, take the first vert refered to by the edge, if negative then take the second (negate the edge index so its positive, but no bias as 0 is always invalid, and -0 can thus never happen). Walk the edges to get the list of verts for each surface.
To determine texture coords, you'll need to do some maths based upon the texinfo[surf->texinfoid] stuff:
vert.s = (dotproduct(texinfo->vecs[0].normal, vert.xyz) + surf->texvec[0].dist) / texturewidth;
vert.t = (dotproduct(texinfo->vecs[1].normal, vert.xyz) + surf->texvec[1].dist) / textureheight;
where dotproduct is of course ((a.x*b.x)+(a.y*b.y)+(a.z*b.z))
the texture index used is refered to via the texinfo object, which is of course refered to by the surface object.
the texture/miptex lump inside the bsp has this form:
int32 numtextures;
int32 offsetintolump[numtextures];
the start of each actual miptex is a 16 byte name, followed by the width and height as int32s, and if you're using unity or whatever then you should probably just use replacement textures and skip parsing beyond those fields, but if you do, there's an additional 4 offsets to the 8bit paletted image data after the height, expressed as offsets from the start of the texture and not the lump, one for each of the 4 mip levels that software rendered quake supported. You can likely just use the first and ignore the others.
 Q3 BSP Header Parsing
#1093 posted by ALLCAPS [174.106.183.23] on 2013/10/04 07:42:21
I decided to swap from using Q1 BSP to Q3 BSP, because there is a lot more documentation on Q3 BSP specs. I'm reading in the bytes for the header and everything looks good except for the first entry in the directory.
The length isn't a multiple of 4. At first I thought it was my code, but I checked the .bsp with a hex editor and it really isn't a multiple of four in the .bsp, and I checked multiple maps. Is this normal?
Is it because it's the entities node, and they're stored as strings/char[]? The spec says each directory's size should be a multiple of 4, and it doesn't say anything about the entities directory being exempt from that.
 Noticed
#1094 posted by ALLCAPS [174.106.183.23] on 2013/10/04 08:08:20
That if I "round up" the size of the entities lump to four bytes it then matches with the beginning of another lump, so perhaps it on specifies how many single character bytes there are, instead of how many four-byte dwords it takes up?
#1095 posted by spike [86.140.151.113] on 2013/10/04 12:03:40
4-byte alignment, not 4-byte length.
 Figured
#1096 posted by ALLCAPS [174.106.183.23] on 2013/10/04 15:14:34
I finishes up extracting and parsing entities before I passed out, and everything seems to be working! Good to have clarification, though; thank you. This is my first time ever trying to decode/parse a binary blob like this, so I'm learning as I go.
 SharpBSP Is Born
#1097 posted by ALLCAPS [174.106.183.23] on 2013/10/05 05:00:52
Here it is. Not finished, but getting there.
https://github.com/mikezila/SharpBSP
Once I have it working well and maybe crank out a winforms application that shows some info about a loaded .bsp I'll make a thread/news post about it.
I use C# instead of C++ partly because Unity3D uses it, and it'll make pulling this data into a Unity game/scene very easy, and partly because I'm a scrub that can't handle C++.
Not that anybody cares, but it's free to take/use/copy/modify.
 Bezier Calculation
#1098 posted by ALLCAPS [174.106.183.23] on 2013/10/08 03:56:20
I've made some pretty great strides in parsing and rendering Quake 3 maps. I've hit a snag, though, and that snag is bezier patches.
Here's a video showing what I have so far, and my issue with the patches:
http://youtu.be/8RfwLP0BrSI
Textures, texture mapping/coords are working 100%. Only textures provided by shaders are not working. Animated textures and billboards aren't implemented yet, either.
But issue is that the code to calculate bezier patches is code I lifed from an article on render Quake 3 maps, and did my best to port from what I assume is C++, to C#.
I used these two documents to parse the .bsp and to try rendering the bezier curves
http://www.mralligator.com/q3/ - Map format details
http://graphics.cs.brown.edu/games/quake/quake3.html - Details on converting the vertex systems/scale and bezier curve code
I'm really stuck, as I don't understand enough about bez curves to write my own implementation. Anyone here worked on rendering them that could lend a hand/advice?
#1099 posted by Spike [86.180.86.17] on 2013/10/08 07:21:37
you don't need patches (they're evil), just use q3map2's -patchmeta argument when compiling maps for your game.
q3map2 will then generate trisoup instead.
 Aces
#1100 posted by ALLCAPS [174.106.183.23] on 2013/10/08 07:55:27
That's great to know, and I'll use that for sure if I develop a Q3 .bsp intending to load it into uQuake instead of actual Quake, but I'm tackling the issue of rendering the patches for the sake of being able to render existing Quake 3 maps that use them.
 ALLCAPS
#1101 posted by metlslime [50.156.87.109] on 2013/10/08 08:45:18
why not look at the quake 3 source code to see how it tesselates bezier patches?
#1102 posted by ALLCAPS [174.106.183.23] on 2013/10/08 13:43:31
My raw understanding of the patches (and C/C++) is very limited, but I will likely have to do that. Right now I'm working on rendering multi-patch faces without any tessellation, just the reference points. I can render single-patch faces, but I'm working on how to extract the 9 reference points from the face, and making an individual patch out of that when there is more than one patch in the face.
Once that is done and references are rendering correctly, the only piece of code that will need changing to have beziers 100% working will be the method that takes those control points and fills the patches vertex and triangle strip data. Getting closer.
 Okay....
#1103 posted by metlslime [159.153.4.50] on 2013/10/08 21:11:11
well if your problem is the theory behind it, maybe i can help a little bit.
First, quake3 patches use bezier curves, which are parametric equations. This means that to generate a point on the surface you need to input a parameter. The parameter can go from zero to one, and as it moves from zero to one the point generated moves along the curve from the start to the end. The parameter is usually called "t".
Second, quake3 patches use quadratic curves, not cubic curves (which are more common i think), so that means they have 3 points to define a curve instead of 4. The three points are startpoint, control point, endpoint.
Third, how to solve a quadratic curve? First, look at this picture:
http://upload.wikimedia.org/wikipedia/commons/2/2d/Bezier_2_big.gif
P0,P1, and P2 are the three control points. Green stuff is intermediate calculations, and the red line is the final curve.
So to solve for the black point (a point on teh curve) you first find a point on the line from p0 to p1, call that A, then find a point on P1 to p2, call that B, then find a point on the (green) line from A to B, that point is your solution (black dot.) In all three cases, when you "find a point" you are finding the point using t -- if t is 0.5, find the halfway point. if t is 0.25, find the point 1 quarter of the way from the first point to the second point.
Okay, assuming you understand all that... the quake 3 patches are 2-dimentional surfaces, not just single lines. So instead of 3 points, they have 9. To solve it you need to do multiple tasks like the one above (solving a simple 3-point curve.) Since it's two-dimensional, to find a point you need two parameters instead of 1 -- instead of t, you need s & t.
Imagine the 9 points are arranged in a 3x3 grid. First row is 1,2,3, second row is 4,5,6, last row is 7,8,9. First solve three horizontal curves using s -- 123 is the first curve, 456 is the second curve, and 789 is the third. Each uses s as the input parameter. Each gives you one new point -- A,B,C. Now solve curve ABC with parameter t. Now you have found a point!
Okay, so now you can find any point on the surface of the patch using s,t coordinates. How to render a patch? What you do is divide the patch into a grid of quads. The vertexes of the quads are determined by inputting s & t. If you want N * M quads, you need (N+1) * (M+1) points. The first point is 0,0 and the last point is 1,1. Intermediate points are evenly spaced in between.
 What A Scholar
#1104 posted by ALLCAPS [174.106.183.23] on 2013/10/10 05:32:58
That helped me so much, that using that info, some time and study, and some patience I have perfected parsing, tessellating, and rendering (with textures!) Quake 3's bezier patches. Huzzah!
http://imgur.com/a/i470V
Textures that are provided by shaders in Quake 3 aren't working for obvious reasons. I also need to debug lightmap ripping/application, but those are pretty minor issues. Unity's realtime and baked lights look better anyway.
Thanks a ton.
 UQuake
#1105 posted by ALLCAPS [174.106.183.23] on 2013/10/10 05:51:40
Here is a link to the github of the project. It's free to do with as you please.
https://github.com/mikezila/uQuake
Don't want to keep mucking up the coding help thread, so if/when I make videos and take screenshots to show it off I'll probably make a new thread.
#1106 posted by metlslime [50.156.87.109] on 2013/10/10 07:42:32
Nice, you got it working! Glad to help.
 Neat!
#1107 posted by FifthElephant [82.24.73.240] on 2013/10/10 12:50:03
Is this a quake 1 engine??
 Unity3D
#1108 posted by ALLCAPS [174.106.183.23] on 2013/10/10 15:04:28
The engine itself is Unity3D, which is a freely available engine that you can use for almost anything. I've built a reader for .bsp files, and a "renderer" that creates the level as Unity gameobjects. It's not a "true" bsp engine because only the geometry is used, things like leafs, nodes, the bsp tree itself, and vis data is not used. Unity handles those things on its own at runtime.
Right now it only supports Quake 3 maps, but I want very much to add support for Quake 1 maps. Once I get lightmaps working on Quake 3 maps I'll set to support Quake 1 maps. My original goal was actually Quake 1 maps, but extracting the geometry from them is a little more complex than Quake 3 maps, so I did this first as a warm up and to see if it was possible.
 Very Cool
#1109 posted by necros [99.227.113.78] on 2013/10/12 00:03:03
nice work figuring it out!
 It's Time For Q1 Support To Begin!
#1110 posted by ALLCAPS [174.106.183.23] on 2013/10/13 03:14:47
Alrighty, Quake 3 lightmap support is done. The colors aren't as vibrant as they should be because Unity's RGB lightmap shaders are lame, but the data is ripped and applied correctly. I also replace shader-modified textures with non-shader versions at runtime. Like on the strange flesh-spire and lava here.
http://imgur.com/tO3SSUP
But like the title says, it's time for Quake 1 support. The most comprehensive guide to the Q1 .bsp specs is here:
http://www.gamers.org/dEngine/quake/spec/quake-spec34/qkspec_4.htm#CBSPG
Is this still current? It's really old, and says it matches the .bsp version used in Quake shareware. Is there a more detailed or updated guide on the .bsps produced by modern compilers?
 Q3 Lightmaps.
#1111 posted by Spike [86.173.175.39] on 2013/10/13 05:07:34
q3 has overbrighting. the lightmap scales between logical rgb values of 0 to 4 rather than 0 to 1. The lazy way to deal with that is to just multiply the values by 4 and clamp to 255. The real way to deal with it is to scale your vertex colours by 4 instead, or to put the same scaling in glsl.
This nonsense allows bright areas to oversaturate textures, thus textures which are grey colours can brighten up to become more white in bright areas.
Software vanilla Quake has a similar feature. vanilla glquake just clamps.
Check some engine's bspfile.h, like that markv_bsp2 zip I hacked together recently if you're after bsp2 support. Otherwise bsp29 is still the same bsp29 that's documented in your link.
 Trianges?
#1112 posted by ALLCAPS [174.106.183.23] on 2013/10/13 20:17:41
Was studying the BSP29 document some, and I realize that nowhere is there a list of triangles for any of the faces. Is there something I'm not seeing, or does it fall to me to figure that out using sorcery?
 I Don't Think Bsp29
#1113 posted by FifthElephant [31.95.21.141] on 2013/10/13 20:22:40
Works like that. It's the .map file that has that info and that is then compiled into a scrambled file?
 Process
#1114 posted by ALLCAPS [174.106.183.23] on 2013/10/13 20:38:34
When I was reading the Q3 .bsp into Unity my process was like this.
Take a face. A face has a list of vertices, and a list of triangle indexes into that faces vertex list. So to make a mesh out of a face all I had to do was make a mesh, and set it's vertex and triangle arrays to the data I pulled out of the face. Each vertex object has data about it's position, texture coords, color, and lightmap coords. The whole process was actually pretty slick.
In Quake 1 it seems like every surface has a list of edges, and each edge has two vertices. Using some simple rules and maths getting a list of verts and the texture mapping info for those verts doesn't seem too hard. So I make a mesh and add the verts and texture coords. But how do I form triangles? In Quake 3 that data was provided for me, but here it's not.
Is each face only going to be three verts? That doesn't seem right. Are the faces always going to specify their verts in the order needed to form triangles out of every three verts?
#1115 posted by Spirit [80.171.95.37] on 2013/10/13 21:39:31
Noesis can load bsp files, you might be able to find well readable code in there. http://oasis.xentax.com
 ALLCAPS:
#1116 posted by metlslime [50.156.87.109] on 2013/10/14 04:36:14
you have to triangulate it yourself, i think. All the faces are convex polygons, so it shouldn't be too hard to triangulate them. Only down side is there may be some degenerate triangles due to extra verts added for tjunctions. I guess you should keep these because otherwise you may get visible cracks.
#1117 posted by ALLCAPS [174.106.183.23] on 2013/10/14 04:40:50
Dang, really? The renderer back in the day mashed out the tris for the whole map each time it loaded? That's unreal.
#1118 posted by metlslime [50.156.87.109] on 2013/10/14 05:39:25
actually the software renderer directly rasterized polygons, so it never needed triangles. Later opengl versions would use GL_POLYGON primitive type, so they didn't need triangles either.
 Well...
#1119 posted by ALLCAPS [174.106.183.23] on 2013/10/14 07:23:31
I guess since every poly is going to be convex I can just ham-hand it and make tris using a pivot point and casting to each other vertex. 0-1-2, 0-2-3, 0-3-4, etc. It's the least efficient way possible, but I guess it's sure to cover the full face. Come to think of it when I r_showtris in some engines it looks like that's what it's doing.
 Efficiency
#1120 posted by SleepwalkR [130.149.243.209] on 2013/10/14 09:52:54
How is this "least efficient"? I don't see a more efficient way to generate triangles from convex polygons.
#1121 posted by ALLCAPS [174.106.183.23] on 2013/10/14 19:41:17
Honestly I just assumed it was the least efficient/elegant way since it was the first solution I thought of. Probably because it's simple. I just figured there'd be a more complex, "better" way.
#1122 posted by Spike [86.180.86.104] on 2013/10/14 20:11:26
each edge has two sides. pick one vertex from each edge based upon the side of the edge you're using. side is determined by whether the edge index is negative or not. this will get you a convex polygon (aka: a triangle fan). more modern renderers can trivially generate triangles from that.
the whole thing is just triangle fans. software kept it like that because its easier to clip+frustum cull, which is part of how it managed to avoid all overdraw from bsps.
remember, these face polygons are never concave. there's no holes or anything. its pretty trivial because of that.
 Efficience Of Triangle Fans
#1123 posted by Preach [77.98.165.95] on 2013/10/14 22:04:35
Strictly speaking there may be an inefficiency there in rendering>/i> those triangle fans. According to a half-remembered article I read a while back, long, thin triangles are slightly less efficient to render than evenly proportioned ones. I'd hazard a guess that's due to better cache-coherence properties of the latter.
I wouldn't worry about it though, primarily because it's a tiny difference. Also because almost all the polygons in quake maps will be 6 sides or less, so there's not a great deal of difference between the best and worst choices.
#1124 posted by JneeraZ [108.228.244.211] on 2013/10/15 00:58:42
This is where I've had the nagging thought that I'll bet modern engines could just create large, texture sorted buckets of triangles representing the entire level and just throw it at the video card. Odds are that on even a mid-level machine, it would run fine.
Keep the BSP for collision checks and line-of-sight stuff, but in terms of raw rendering I wonder if parsing through the VIS data is actually a detriment these days.
 You Know...
#1125 posted by Spiney [91.179.146.226] on 2013/10/15 01:20:53
Brute forcing winning over the elegance of a BSP traversal algorithm always felt like an aesthetic unfairness to me.
Not that I mind scraping the vis times.
 Almost Reads Like A Carmack Tweet
#1126 posted by Spiney [91.179.146.226] on 2013/10/15 01:23:22
I need to get some sleep
 BSP
#1127 posted by Preach [77.98.165.95] on 2013/10/15 08:42:09
Remember that visibility tests aren't used exclusively by rendering - they're also used by the ai as the first step of deciding if the player can be seen or not. So you will take a double hit on performance as every monster in the level starts doing traceline visibility test every frame.
Of course, it's pretty easy to test the hypothesis that vis is unnecessary - just build a map, saving a copy of the un-vised BSP file as you go. Then compare performance across the two files. You could even run vis at all the different levels and have multiple points of data. I don't know if there's any hard data on how much of a fps gain you get from making vis more accurate, it might be thaat they highest levels don't provide a good return on investment.
 TrenchBroom Does The Brute Force Thing
#1128 posted by SleepwalkR [92.231.226.153] on 2013/10/15 12:02:44
It just throws texture-sorted triangles at the GPU, and it's pretty fast. The only drawback is that you have to reupload a lot of data to the GPU when the user changes the geometry, but since usually only a few brushes are selected at a time, just uploading the selected geometry is fast enough.
#1129 posted by JneeraZ [108.228.244.211] on 2013/10/15 13:28:07
Preach - You'd need an engine change to test it properly. If it's traversing the BSP tree to gather up the triangles every frame then it's still eating overhead that a bulk renderer wouldn't have.
I wonder about the hit there though, on your monster example. Line traces in a BSP are extremely fast. But pre-computed VIS data is always going to be faster there. The problem is that it would take a lot of work and engine coding to come up with a definitive test. :P
Sleep - That's what ToeTag did as well. I think there was a basic cull for stuff entirely behind you, but that was about it. Everything else got chucked at the card, sorted by texture. I never really saw it slow down at all...
 UQuake Performance
#1130 posted by ALLCAPS [174.106.183.23] on 2013/10/15 19:05:30
uQuake leaves all that up to Unity to handle, it discards the bsp tree itself, the vis data, nodes, planes, all that jazz. Unity decides per GameObject what should be rendered and what shouldn't, and with each face/patch its own GameObject it can cull invisible regions and polys very well. In essence I'm throwing the entire level at the engine at once, but the engine is good at throwing only the parts that can be seen right now at the video card. Works well even on an Ouya/HP Touchpad, which are some Android devices with less than amazing GPUs. The Ouya version of uQuake renders and empty level faster than the proper port of OpenArena, even, which I'm pretty sure uses the vis-and-related data to do traditional bsp stuff, as it's a source port.
I am hitting some issues with parsing Quake1 .bsp, though. Perhaps my understanding of variable type and size is not correct, but the file specs I linked above say that a face is thus:
u_short plane_id;
u_short side;
long ledge_id;
u_short ledge_num;
etc...
u_shar light[2];
long lightmap;
Is an unsigned short int not two bytes? is a long not eight bytes, and a char one? I try to read the data out using that assumption and I get garbage. Looking at the offset where faces start It looks like either the specs are not right, or a short is one byte. I did notice the the BSP version in the file is 29 while the spec here is for version 28.
 .h
#1131 posted by ALLCAPS [174.106.183.23] on 2013/10/15 21:28:52
comparing with Quakespasm's structs in bspfile.h it looks like they are different. The doc at gamers.org shows a different number of fields than the struct in Quakespasm, with different types as well.
 Unity
#1132 posted by Kinn [109.151.156.132] on 2013/10/15 23:39:22
and with each face/patch its own GameObject
Seriously? o_O And Unity handles that ok?
I've been doing similar stuff (parsing a doom3 .proc file into unity meshes) - the great thing about .proc files is that the surfaces are already grouped into the areas that are created by doom 3's visportals. I typically create just a single combined mesh for each of these areas. If I want more granularity to the meshes I'll just stick in more visportals.
 Oh Yeah
#1133 posted by ALLCAPS [174.106.183.23] on 2013/10/16 01:11:51
Unity can handle a ton (10k+) of simple gameobjects without issue. I'm not sure how well it'd work if each gameobject had logic/tags/scripts attached, but just using them to render meshes has almost no overhead. I'm pretty sure Unity groups batches of meshes into drawcalls anyway. I've loaded some Return to Castle Wolfenstein SP levels that ended up being about 10k gameobjects, and only got slowdown if I selected worldspawn (so, every single face in the level) in the editor with the game unpaused. Rendering the level was still working great.
 Hmmm
#1134 posted by Kinn [109.151.156.132] on 2013/10/16 22:14:04
I guess unity has ways of optimising static gameobjects - I'll have to find out more about what it's actually doing.
On another note - how are you handling the map collision?
 "is A Long Not Eight Bytes"
#1135 posted by mwh [120.136.5.22] on 2013/10/17 00:39:06
Probably 4 bytes? Quake was released >5 years before the first amd64 cpu after all :)
#1136 posted by necros [99.227.113.78] on 2013/10/17 01:01:42
when i was parsing mdl files, ints were 4 bytes so longs probably are 8.
 Kinn
#1137 posted by ALLCAPS [174.106.183.23] on 2013/10/17 04:36:45
Every GameObject has a mesh collider on it! Each object gets:
- A material that's created at runtime using the texture I ripped from from pak0.pk3 and the lightmap decoded from the .bsp, using a shader I found on the Unity forums.
- A mesh that's generated at run-time using the verts and tris from that face's entry in the .bsp. I call .Optimize and .RecalculateBounds on each mesh as it's generated. I'm not sure if this is needed or not.
- A mesh collider, which is the slowest type of collider Unity has, but since each face is typically small, and is sure to be convex, it's actually pretty fast.
I had planned to implement the bsp tree to help reduce the number of gameobjects, but it looks like Unity does a fine job on it's own. I've run a bunch of the stock Q3 maps and some pretty sizable custom ones on both a crappy laptop with a Core Duo and ancient Intel graphics, and on the Ouya, which has a terrible Tegra3, and it runs very well on both. I suspect Unity does it's own judgement on what objects need to be rendered and what colliders should be checked against, and it seems to scale very well.
 Int+long
#1138 posted by ALLCAPS [174.106.183.23] on 2013/10/17 06:35:37
From QuakeOne.com forums:
byte+char are both 1 octet, short is 2 octets, int+long are both 4 octets, long long is never encountered.
Octets in this context being equal to one byte.
 ALLCAPS
#1139 posted by Kinn [80.247.24.248] on 2013/10/17 11:13:03
Ah ok, so your collision mesh is just a duplicate of the render mesh essentially.
I was just wondering if you'd found a way to somehow process the bsp collision data, so you could take advantage of clip brushes etc, which would simplify the collision geometry somewhat.
#1140 posted by ALLCAPS [174.106.183.23] on 2013/10/17 15:49:18
In theory you could just skip adding mesh colliders to the faces as you made them, and then create meshes from the bsp brushes in the map, and a collider to them, and skip adding a renderer, so you have an invisible clipping brush. That would be needed for sure on some maps, where simplified collision stops the player getting hung up on detail in the map.
 Progress!
#1141 posted by ALLCAPS [174.106.183.23] on 2013/10/17 19:41:35
I have it mostly working. Geometry is recreated, and texture coords are calculated correctly. Or at least I think they're correct, they scale and move like I expect them to playing around with them in trenchbroom.
Getting verts for each face was a little confusing at first with the double-lookup method it requires, but it wasn't that difficult. Same for texture coords; a little confusing at first, but simple in the end.
As a stress-test I loaded up Sock's Ivory Tower, and the result is a CRAZY 32k GameObjects!
THIRTY. TWO. THOUSAND. OBJECTS.
http://imgur.com/sNHWsmf
Marking the objects as static lets Unity batch them together, resulting in only about 2-5 draw calls at any given moment. It's very slow to start up, likely because right now I am making a ton of Lists as I make each object, which was helping me squash bugs. Now that I have the process down I think I'll be able to simplify it and speed up startup.
Getting there!
 Nice!
#1142 posted by ijed [190.22.1.99] on 2013/10/17 19:55:29
Congrats on that.
Qunity Quanity Quakity Quakey...
About collisions, I thought the whole saving of visual / hull collision was marginal anyway by modern tech? Does / would it have any discernible impact on modern machines?
 @ALLCAPS
#1143 posted by sock [190.139.230.15] on 2013/10/17 20:32:21
If you really want something to stress test your unity map converter program I recommend you try my Map on the Edge of Forever. All of the source files are freely available, it has full HD textures and new environment sounds with spoken dialogue.
If you can get some simple game logic (pushing/shooting buttons) and Q3 style shaders working it would easily run standalone in Unity!
#1144 posted by ALLCAPS [174.106.183.23] on 2013/10/17 21:02:34
@ijed
Really there's no performance need to have simplified colliders anymore, at least not using Unity. The main benefit would be to stop players from getting stuck on detailing. Players love to glide along walls and assume they'll just slide along the wall without getting hung up on the grates and torches.
@sock
Would love to have larger maps like this working well. I'm going to have need some optimization before I get big maps working well.
I replaced all of my Lists with arrays in the object generator, but startup performance with large maps didn't increase much. Premature optimization is the bane of many a project, though, so I think I'll focus on getting smaller maps (like my lame remake of dm_stalwart) working with textures and lightmaps before I start looking to juice performance.
#1145 posted by Spike [86.182.64.238] on 2013/10/17 22:17:19
brushes help with water+fog volumes.
oh, and good luck with clip brushes in q1 maps. :P
 If You Need
#1146 posted by ijed [186.79.204.209] on 2013/10/17 23:51:20
Really big maps then let me know :)
Would all be in bsp2 format, if that makes any difference.
 BSP2
#1147 posted by ALLCAPS [174.106.183.23] on 2013/10/18 01:19:46
Not sure how it would react to a BSP2 map. Could you link me one? Just got textures working and would love to give it a whirl.
On the topic of textures, I have them reconstructed correctly. I went full old-school and created textures by using the indexs from the .bsp into the genuine palette.lmp. I'm sure I could have dumped the textures and done some kind of substitution, but with how every Q1 .bsp has its texture data embedded, it'd be a shame to not be able to just load any .bsp and use what's already included. Plus it's more authentic this way, ensures that the texture colors are pixel perfect.
What's not pixel perfect is the scale of the textures. I've used the dotproduct to generate the texture coords for the verts, and they are rotated correctly, and their scale does change how it should when I adjust it in trenchbroom, but they still need to be scaled up, there are too many tilings of a texture on any given surface.
I noticed that it says to divide the result of the dotproduct by the texture width. Could you elaborate on this a little bit? I'm trying to do that, but I end up with a strange minecraft-esque texture.
 Ivory Tower
#1148 posted by ALLCAPS [174.106.183.23] on 2013/10/18 01:31:02
Screenshot showing ivory.bsp loaded:
http://imgur.com/DukiW4C
Not going to be able to rely on Unity's batching to save me, since all the textures are generated at runtime. Will think of something clever, I'm sure.
 Here's Tronyn's Bsp2 Map
#1149 posted by ijed [186.79.204.209] on 2013/10/18 02:19:41
 Textures Working Great!
#1150 posted by ALLCAPS [174.106.183.23] on 2013/10/18 05:56:42
I have textures working perfectly now. Scaled and everything. The Ivory Tower is looking much better!
http://imgur.com/ueMK4Qa
The only bug I'm running into now is when I try some maps from Quaddicted. Some (most older) maps don't load because I end up with invalid texture dimensions.
Newer maps are working fine. Here's Q-Deck.
http://imgur.com/dt9JFcW
Some old maps work fine. Like this one: https://www.quaddicted.com/reviews/deso.html
I've noticed in maps that don't work that there are textures that start with z that seem to be the only ones getting incorrect data pulled. An example is https://www.quaddicted.com/reviews/fmb6.html
Anyone have any insight into this? It doesn't seem to be me reading the wrong size data, as the textures in the map that don't start with z read correctly, and show sane dimensions and offsets. It's only the "z" textures that are screwy.
 Github
#1151 posted by ALLCAPS [174.106.183.23] on 2013/10/18 06:00:50
Here's the github for this if anyone is interested. Just like the Q3 version it's free to fork/copy/whatever.
https://github.com/mikezila/uQuake1
#1152 posted by Spirit [80.187.104.105] on 2013/10/18 09:29:49
For the thousandth time, tronyn's is NOT BSP2, it's 2PSB.
 Chill The Funk Outsiders Spirit
#1153 posted by ijed [186.79.204.209] on 2013/10/18 12:17:27
(Think I'll let the weird Spanish translation stand for that one)
ALLCAPS, I can send you a true bsp2 map in a couple of hours; back to the office today.
Do you just need the bsp?
#1154 posted by ALLCAPS [174.106.183.23] on 2013/10/18 13:32:02
Yes, just the .bsp itself.
 I Linked
#1155 posted by ijed [200.73.66.2] on 2013/10/18 14:05:35
The dropbox folder (mail etc. sent).
The BSP inside 'should' always be a fullviz, if that matters to the port process.
If not then I can upload one quickly enough - it takes about 10 minutes to compile, using Tyrann's tools.
 Vis
#1156 posted by ALLCAPS [174.106.183.23] on 2013/10/18 15:15:01
Vis data is not used (or even parsed) currently, so that won't matter. I do plan to implement it in some capacity, but haven't yet. Trying to tackle the performance of loading big maps first, so that I don't end up having to refactor a bunch of stuff. I suspect implementing vis will cause/require me to change how I generate my objects, and before I do that I want to see what performance gains I can get.
 Ok
#1157 posted by ijed [190.21.114.26] on 2013/10/18 15:38:32
What's in there should definitely work as a decent benchmark then.
 ALLCAPS
#1158 posted by Kinn [80.247.24.248] on 2013/10/18 18:12:41
If your meshes were grouped together better, then I'm sure you could use unity's occlusion culling feature (pro unity only tho)
 Stuff
#1159 posted by Kinn [80.247.24.248] on 2013/10/18 19:01:05
In theory you could just skip adding mesh colliders to the faces as you made them, and then create meshes from the bsp brushes in the map, and a collider to them, and skip adding a renderer, so you have an invisible clipping brush. That would be needed for sure on some maps, where simplified collision stops the player getting hung up on detail in the map.
If you have access to the .map file, and use the brushes in the .map file to generate the collision meshes, then a couple of things occur to me:
1) You could detect which brushes are essentially boxes (probably a lot of them), and use box colliders for them instead of mesh colliders.
2) The non-box brushes are still guaranteed to be convex, so you can enable the convex flag on their mesh colliders, which I'm sure helps.
#1160 posted by ALLCAPS [174.106.183.23] on 2013/10/18 19:46:44
Hmm. Doesn't the .bsp have primative bounding boxes in it for fast collision testing? Maybe I'm thinking of the wrong thing. I didn't mean to use the .map to create boxes from brushes, I thought they were in the .bsp. I think I used the word "brush" when I shouldn't have, causing confusion.
I hadn't even thought about marking the mesh colliders as convex. That's a great point. I'm about to start doing some System.Stopwatch tests to see what takes the longest and what is worth it to optimize and what isn't.
Still haven't looked into lightmaps, but from a cursory glance it looks like they're not going to be simple; at least not as simple as Quake 3's were.
#1161 posted by Spike [86.173.174.105] on 2013/10/18 21:12:11
no. bounding boxes in bsps are for frustum culling. they're not useful for collisions as the bsp tree will cull all that effectively enough anyway.
 Vis Data
#1162 posted by ALLCAPS [174.106.183.23] on 2013/10/19 03:19:28
Trying to parse the vis data, and I'm trying to verify that I correctly understand the run-length encoding used. Consider:
10100010
Would that RLE to
1010310
or
10100310
Some places say that Quake vis data only does RLE on runs of zeros, but the only doc I have is the one that has proven to be very outdated.
 Oh Shit
#1163 posted by ALLCAPS [174.106.183.23] on 2013/10/19 03:31:34
Can a face be part of more than one leaf?
 UQuake QTest
#1164 posted by ALLCAPS [174.106.183.23] on 2013/10/19 06:45:51
I've sped up start up dramatically. Replaced all remaining Lists with length initialized arrays. This cut startup time on ivory.bsp (which as become my benchmark) from two and a half minutes to two and a half seconds.
I also detect clip/skip faces and don't render them, which makes maps a lot more fun to fly around!
Here is a build for you guys to test out and play with:
https://dl.dropboxusercontent.com/u/5408868/qtest.7z
I've included Sock's ivory.bsp as the default map because it is awesome, and I used the spectacular rockwork to test/verify my texture creation/application was working right, which it is.
If you'd like to try a different map, open the "assets/resources/maps" folder and name the map you'd like to try "map.bsp" and it'll be used. The camera will spawn at the world origin. Mouse1 will move you forward, Mouse2 backwards. No WASD, just mouselook.
Currently there is no vis consideration at all, so what is being rendered is up to Unity. This isn't ideal at all, so the map might chug if your video card isn't up to it. Give smaller maps a try!
Currently only BSP29 maps are supported, but BSP2 support will be trivial to add. I'll do it next session I think, to take a break from fighting with vis data.
 ALLCAPS
#1165 posted by spy [178.88.89.40] on 2013/10/19 07:47:01
Could you explain, what the main purpose of that uQuake util
 Ooch
#1166 posted by spy [178.88.89.40] on 2013/10/19 07:50:48
Doesn't run on my rig
 Won't Run
#1167 posted by Kinn [86.152.222.137] on 2013/10/19 12:02:58
not a valid Win32 application apparently.
 64 Bit
#1168 posted by ALLCAPS [174.106.183.23] on 2013/10/19 14:25:53
Sorry forgot to mention that build is 64-bit only. I'll build a 32 bit version.
Honestly I'm not sure what the ultimate purpose is/will be. Really I'm just doing it because it's fun to make. Though Unity runs almost everywhere (Windows, OS X, iOS, Android/Ouya, web browser, Windows Store/Phone, etc) so if I can pull it off the end result will be a (free) Quake engine for a bunch of devices. Really now I'm just doing it as a programming project based around one of my favorite games.
 Visual C++ Redist
#1169 posted by ALLCAPS [174.106.183.23] on 2013/10/19 14:35:41
You might also need the Visual C++ runtime on 64 bit, which is here (it's tiny) http://www.microsoft.com/en-gb/download/confirmation.aspx?id=14632
 Blogs Again
#1170 posted by Preach [77.98.165.95] on 2013/10/19 16:21:43
Not had much chance to get things on my blog recently, but put out a short article today.
http://tomeofpreach.wordpress.com/2013/10/19/random-entities-find/
It's a combination of a neat mathematical trick and a little bit of glue code which allows you to select one entity at random from find or findradius result sets. There's also a pattern at the end for writing find loops, so you don't have to repeat your find code at all. Whether it's an actual improvement or not is up for discussion...
 32/64 Bit Builds Of UQuake
#1171 posted by ALLCAPS [174.106.183.23] on 2013/10/19 23:18:06
Sorry for the 64-bit snafu. Also sorry for using Dropbox, it's not the best for sharing public files. Lets try Github instead.
https://github.com/mikezila/uQuake1/tree/master/Builds
Pick your favorite flavor, 32 or 64. You might need the Visual C++ 2010 runtime if it complains about Mono.
 VIS Approach
#1172 posted by ALLCAPS [174.106.183.23] on 2013/10/20 18:57:31
I'm thinking on the problem of using the vis data from the maps in my renderer, and I'm running into a few snags. Some of these snags are no doubt a result of me trying to take shortcuts.
At first I thought I could use the bounding boxes for the leafs, and just check against them using the player/camera position. This would make it very easy, as each leaf knows what other leafs to render. Problem is that the only bounding boxes in the .bsp are stored as shorts, not floats. The problem with that is that to convert "Quake space" to "Unity space", I have to scale (and rearrange) the vector3s by 0.03! That's a pretty extreme scale, but it wouldn't be a problem if the bounding boxes were stored as floats, but they're not. Once I do this scale, the boxes are not accurate enough, they're obviously off center, and not shaped/proportioned correctly. I thought I could work around this by making a bounding box myself that encompassed all of the faces in a leaf, but there is a lot of overlap in many places, even if I just overlap the center of the faces and not their whole bounds. On the plus side I accidentally made a pretty nice tool to check if parts of your map geometry are producing shitloads of leafs.
I also made a bad assumption that a given face could only be a member of one leaf, but it looks like that's not the case. I should have known better, as if a face could only be in one leaf it'd probably be listed in the face struct.
Is there any shortcut I can take, as opposed to just implementing the bsp tree wholesale? I'm thinking pretty hard, because with all the modern tools available it seems like it'd be easy, but I can't come up with anything.
#1173 posted by JneeraZ [108.228.244.211] on 2013/10/20 19:01:02
It sounds at first blush like you're doing something wrong with the bounding box scaling. Scaling it should be perfectly doable without it shifting off center. There must be an incorrect assumption you're making there or something.
 Yup
#1174 posted by SleepwalkR [92.231.104.1] on 2013/10/20 20:03:24
I agree with Willem, are you sure you are not somehow casting the result of the scaling back to short? Although if you multiply a short and a float, the result should be a float, also.
 Botched It
#1175 posted by ALLCAPS [174.106.183.23] on 2013/10/20 21:11:34
Yeah I was botching it. I was reading the 12 bytes that contain the shorts and passing them to be handled by the leaf constructor, but in that constructor I was only using the first six bytes to make my six floats (ugh). Corrected that and now the boxes are placed and rendered correctly. I'm currently fighting with Unity's local vs worldspace shenanigans, but it looks like this might just work.
Thanks for calling me out on my assumption.
 Find-tuned Looping
#1176 posted by yesterday [91.125.157.168] on 2013/10/20 23:47:14
There's also a pattern at the end for writing find loops, so you don't have to repeat your find code at all. Whether it's an actual improvement or not is up for discussion...
How does it compare to using a for loop to find, instead?
#1177 posted by Preach [77.98.165.95] on 2013/10/21 08:58:43
How does it compare to using a for loop to find, instead?
It generates essentially the same code, so it's just a trade-off in human terms. The for loop is a bit more explicit on what's going on, but the while loop is shorter and better from the Don't Repeat Yourself point of view.
 Qccs
#1178 posted by Spike [86.163.86.253] on 2013/10/21 18:52:03
your two loops are not equal. the for loop will ensure initialisation.
the while loop will run slightly faster - the way its written will consume one less instruction (additionally the progs will be a smidge smaller due to the reduced repeats).
modern qccs (including recent fteqcc builds) will be able to optimise more agressively if all locals are initialised before use, reducing the number of temps used (because initialised locals will not have undefined values when recursion or overlapping is used). Plus its good practise if you ever write C code. :P
Also, fteqcc likes to warn about unintended assignments within conditionals, which can be fixed with an otherwise redundant extra parenthesis (consistant with gcc).
Put that all together and the ideal loop is something like:
for(candidate = world; (candidate = find(candidate,classname,"monster_ogre")); )
{
foo(candidate);
}
Yeah, it costs an extra vm cycle, and an extra instruction to go with it, but it potentially saves as many 'globals' as you have locals in your function, including localised temps (assuming the qcc doesn't detect any other uninitialised locals).
It definitely saves a few headaches too, when you use the same variable in multiple loops in the function.
Of course, if you want compatibility, the for loop is an extension. Only while and do while loops are supported in all qccs.
 A View Into The Optimisation Process
#1179 posted by Preach [77.98.165.95] on 2013/10/21 22:58:13
That's interesting to know, thanks! So if I explicitly initialise a local I get can get a reduction in stack size. Is that at the cost of additional length in function size? I think it's right that the extra instruction doesn't cost execution time because an extra temp would also mean an extra zeroing-out. Guess there's no benefit if you're not under pressure for temporary variables in that function?
The ability to suppress the warning is a massive boon though! I'm back down to zero warnings and blissful silence...
 Random Query
#1180 posted by Preach [77.98.165.95] on 2013/10/21 23:49:18
Are there any occasions where the optimising code takes advantage of "leaf functions" i.e. functions which call no other functions? It seems like a category of function which would be easy to identify at compile time, and where you could go very aggressive in terms of reusing variables as you don't have to worry about recursion or anything needing to be restored later...
#1181 posted by Spike [86.163.86.253] on 2013/10/22 00:35:41
QC stack:
when a function is called, the current locals are copied off to some hidden stack. the 'globals' (globals is definitely the wrong word to use here... in this post this is the only meaning of the word 'global') that hold the locals are not overwritten automatically when the function then runs.
when the function returns, the globals that are used for the function's locals are reset to their original values, thus they are cleared or so again ready for the next time its called.
if you have a recursive function, those locals will thus be set to the value they had in the parent (even if its not the direct parent). which is probably not what you want.
the optimisation the qcc is trying to use here is to overlap all locals from all functions using the same set of globals. this means you don't waste globals on other things. the engine still does the same amount of archiving (to preserve the caller's locals), just it deals with the same block every time.
the requirement that things are manually initialised avoids bugs with legacy code where unitialised variables are expected to be 0 (despite there being cases in vanilla where they are not - recursion).
Where the function looks like it has at least one uninitialised (read-before-write) local, the function's locals are given a unique non-shared location for all of its locals, as the engine supports only a single globals block for the locals stack.
While its possible that better cache utilisataion might make the code faster, the reality is that the actual cpu will need to execute more instructions than it previously would have.
 Wow
#1182 posted by Preach [77.98.165.95] on 2013/10/22 09:14:36
That's a fascinatingly weird glitch I'd never heard of before - I'd held the zero initialisation as being a fundamental property of the language! For those who like demonstration code, the following shows off the important properties:
void() Recurse =
{
local float delta;
// note we use delta here uninitialised on the
// RHS before the assignment happens
delta = delta + 1;
dprint("IN: ",ftos(delta),"n");
if(delta < 5)
Recurse();
dprint("OUT: ",ftos(delta),"n");
}
This outputs:
IN: 1
IN: 2
IN: 3
IN: 4
IN: 5
OUT: 5
OUT: 4
OUT: 3
OUT: 2
OUT: 1
The value of delta is retained between calls as we recurse deeper onto the stack, but is restored to the value the caller had when we return to her. No doubt someone can do something creative with this, I'm gonna go audit all my code for correctness again...
 Sidenote
#1183 posted by Spike [86.139.74.168] on 2013/10/22 12:40:33
the prerelease had no local stack. Essentually it had no locals at all.
carmack really loved his globals...
Using fteqcc, try:
#pragma warning enable F302
Might have false positives - but let me know if you do spot any false negatives.
 Yeah
#1184 posted by ijed [200.73.66.2] on 2013/10/22 13:42:29
I assumed '0' was correct behaviour.
What would coders expect to be correct for an undefined variable? A null value?
#1185 posted by Spike [86.139.74.168] on 2013/10/22 14:21:39
I don't get what you're asking.
An undefined variable would be a compile-time error.
 I Only Dabble
#1186 posted by ijed [200.73.66.2] on 2013/10/22 15:13:32
In code.
When defining a local value in a function, it defaults to 0 until I set it, correct?
I might be missing the gist of the post entirely.
#1187 posted by Spike [86.139.74.168] on 2013/10/22 16:28:24
The QCVM initialises locals on return rather than on entry. This means that locals *typically* default to whatever the qcc assigned for them, with 0/null/world if it was uninitialised.
The exceptions are when recursion is involved, in which case it starts with the value it has in the earlier instance of the function on the stack (even when its not the direct caller).
Or when the qcc bugs out and tries to reduce local use even when its unsafe to do so, in which case the locals will have pseudo-random values depending upon the values in the same slot in the caller.
Note that:
float a=5;
is technically an initialisation and not an assignment. This means that if you stored something else into a in a parent function, the value of a will NOT start as 5.
Note that vanilla qcc also then considered 'a' to be a constant and then merges it with other constants with the same value, which can mess stuff up quite a lot and is just unsafe however you look at it.
FTEQCC will internally use assignments instead of initialisers if the local is a variable and not a const. If you want the broken behaviour back, you can just define the local as 'local const float a=5;' instead.
Assuming var and using assignments instead of initialisers also allows 'float speed = vlen(self.velocity);' as valid and well-defined code, which is the main reason for the behaviour change. :P
 Ah
#1188 posted by ijed [200.73.66.2] on 2013/10/22 17:21:34
I use FTEQCC and also the broken format, just because that's what I've learned from looking at other code.
#1189 posted by Spike [86.179.108.15] on 2013/10/22 22:55:41
yeah, that last paragraph was to say 'except in fteqcc, initialised locals work as expected', so no worries.
might not be 'standard' (if such a thing even still exists), but its more useful and intuitive.
 An Open QC Question...
#1190 posted by Preach [77.98.165.95] on 2013/10/25 00:44:35
I have a suspicion that the answer is going to be no going into this one, but here goes. Does anyone know of an engine-neutral trick to distinguish BSP models from non-BSP models in QC. Apart from the obvious way of trying to make them SOLID_BSP and checking to see if you've crashed...
I can think of a few heuristics that might imply BSP models based on the maxs and mins, but none that would be anywhere close to reliable enough. Mins and maxs have also varied in the past between different custom engines, so it doesn't seem very safe.
You might try incredibly ugly hacks in QC to increment the pointer to the modelpath string one character at the time. By running a few string comparisons at each step you should eventually get a match to one of the file extensions. Apart from the danger of making a mistake in the pointer arithmetic and causing a segmentation fault, this method would fall foul of someone who lied about the extension of their model!
It turns out Quake engines don't actually rely on the extension for determining the model format - instead they read the magic number at the start of the file. This is a piece of good fortune for people who create md3 replacement models for advanced engines, as they can match the names of the original files yet use the replacement format.
I did scour the codebase a little while looking for any places the crucial difference between a .mdl and .bsp format model poke their heads out, but I couldn't see anything. Any thoughts?
 Make A Working Model?
#1191 posted by yesterday [91.125.157.168] on 2013/10/25 01:59:53
About the only thing I can think of is testing the model for crashes while not running in a live environment, but that's hardly a helpful solution.
I'm wondering now why this might matter, though. About the only plausible guess I have is that you're trying to make Quoth's .mdl box items lit properly.
 @preach
#1192 posted by Spike [86.183.24.134] on 2013/10/25 02:49:42
Vanilla NQ code will *always* set mdl format's size to '-16 -16 -16' '16 16 16'. A poor choice, but lovely and consistant. Failure to do so still breaks mods.
This size is distinct from all vanilla .bsp models, which have a mins of '0 0 0'.
Sadly, third-party engines fix that (no more dodgy frustum culling), but gain qc bugs as a result.
In DP, you'd need to set sv_gameplayfix_setmodelrealbox to 0 first. Its now the default but wasn't in slightly older versions.
In QW, setmodel *only* does setsize for actual bsp models. mdl models are not actually supported/loaded by QW servers. Sadly it uses the extension to see if it should try to load a bsp... But, if its foo.bsp you can use this to check its actual type.
There's a couple of extensions lying around like DP_QC_GETSURFACE's getsurfacenumpoints(ent,0) that will return 0 for non-bsp formats, until it gets extended to work with other formats too... :s
Other than that, a model format is a model format. QC defines the physical size of the object (to avoid bugs), and the model itself provides just the mesh.
The only time you'd need to be able to tell the difference is when you have something like func_trains which expect bsp objects. I suggest you use spawnflags or something to say 'non-solid' instead. You'd need to modify the qc code to add a non-inline precache anyway.
 Thanks
#1193 posted by Preach [77.98.165.95] on 2013/10/25 10:25:11
The only time you'd need to be able to tell the difference is when you have something like func_trains which expect bsp objects. I suggest you use spawnflags or something to say 'non-solid' instead.
That's exactly the scenario I had in mind. It seems like it would be annoying to users that even though you've obviously specified a non-BSP model, you also have to manually tell it "this is a non-BSP model" again. It would be nice to have the mod take the hassle out, or at least practice look-before-you-leap, but I suppose the crash is instant at least so people would catch and fix places where they forgot more or less instantly.
I have a plan in mind now that's slightly neater than a spawnflag...watch this space.
#1194 posted by Spike [81.151.32.243] on 2013/10/25 22:56:28
some engines support non-bsp objects as SOLID_BSP pushers (even if its just a bbox). A non-solid flag should thus not be implied by the model type alone.
You wouldn't be saying 'this is a non-bsp model', you'd be saying 'this isn't solid', which might apply for evil trains too (mwahaha). The fact that the engine doesn't support solid trains isn't the mod's fault, its the engine's fault. That said, the mod probably should take efforts to ensure the bbox size is also tweakable if its a solid mdl.
 Fair Enough
#1195 posted by Preach [77.98.165.95] on 2013/10/25 23:06:01
I think the plan will work just fine with that - people will be able make something that works in all engines or opt for taking advantage of a new engine's features - if they don't mind they've excluded classic engines in the process.
 BSP Tree Traversal
#1196 posted by ALLCAPS [174.106.183.23] on 2013/10/29 21:37:15
I just want to make sure I'm doing this correctly, before I begin my bug-hunt.
To find the leaf the player is in, you take the root node, and see what side of that node's plane the player is on. If they're on the positive side, do the same using node children[0], if they're on the negative side, do the same using children[1]. During this "walking" you'll come to a point where the child you're told to check is a negative number. Discard the negative sign and add one. This is the leaf the player/camera is in, and using that leaf's PVS will render all leafs visible from that point.
Is this right, or am I making a poor assumption or oversimplification somewhere?
 @allcaps
#1197 posted by Spike [86.140.149.18] on 2013/10/30 02:48:06
Discard the negative and subtract one, if you're using that order of operations.
-1 maps to leaf 0, not leaf 2.
Remember to decompress your pvs.
 Roger
#1198 posted by ALLCAPS [174.106.183.23] on 2013/10/30 06:33:00
Got my bsp walking working. I can tell what leaf the camera is in now. Struggled for hours, then on a whim tried inverting the plane normal, and it now works as it should.
Nearly 100% of the stumbles I've run into have been in converting Quake-space to Unity-space, and the trend continues.
Working on decompressing and using PVS now. So close I can taste it. I keep saying I need to work on lightmaps, but this is more interesting. Lightmaps should (should) be pretty trivial, so blazing through that will hopefully be my reward for getting PVS working.
 Conflicting Documentation
#1199 posted by ALLCAPS [174.106.183.23] on 2013/10/30 08:41:05
I'm reading all over trying to get a handle on reading and decompressing PVS data, but I'm having a hell of a time.
I have some embarrassingly elementary questions.
I read out the bytes in the vis data lump, and for the tiny map I'm using to debug this renderer, I get this:
255 10 255 2 207 10 207 10 243 2 243 2 255 10 255 10 0 1 15 255 15 0 1 7 205 11
What is the correct method for decompressing this? I'm not even sure I'm reading it out correctly, because looking at this it looks like there's going to be way too much data. This map only has 13 leafs, so something is wrong. Should I be reading these as shorts/ints instead of raw bytes?
This is an area where examining bspfile.h hasn't really helped, as there's no lump defined for this.
#1200 posted by metlslime [50.156.87.109] on 2013/10/30 09:37:54
look at Mod_DecompressVis in the source, that's where quake decompresses it.
Basically non-zero bytes are uncompressed. Every run of zeros is run-length encoded, a zero followed by a second byte which is a count.
And once uncompressed, there is 1 bit for every leaf.
#1201 posted by ALLCAPS [174.106.183.23] on 2013/10/30 10:18:43
I've tried looking over other source for this, but I'll admit I don't know C well at all, so I can't really follow what's happening.
 Allcaps' Assumptions
#1202 posted by ALLCAPS [174.106.183.23] on 2013/10/30 19:49:49
It's time for another episode of Allcaps' Assumptions.
I have a very small map I made for testing. It has 13 leafs. The visibility lump for this map is 26 bytes.
This means that in order to store a bit for every leaf, each leaf's PVS will be two bytes of data. (13 bits needed, add 7 then divide by 8 to find the number of whole bytes needed) Right?
Parsing the lump, should each byte be interpreted as a char, or an integer? I know that it represents bitfields, but no matter how I read this in it doesn't look at all like I expect it to going by various docs I can find. Reading the small map above's vis lump as chars gives me this:
10 2 10 10 2 2 10 10 0 1 15 15 0 1 7 11 0 105 0 0 123 10 34 115 112 97
This looks kind of okay. So I break it into two-byte sets (since each leaf's pvs is 13 bits, needing two bytes) and get:
10 2
10 10
2 2
10 10
0 1
15 15
0 1
7 11
0 105
0 0
123 10
34 115
112 97
Now it looks less okay. How can there be a set that is 0 0? How can there be 0 105? So there's a hundred and five zero bytes in that set? I'm going wrong somewhere pivotal and I'm really lost as to where.
#1203 posted by gb [46.142.22.45] on 2013/10/30 22:15:30
For the thousandth time, tronyn's is NOT BSP2, it's 2PSB.
Heh.
heh heh heh.
:-D
#1204 posted by Spirit [80.187.109.121] on 2013/10/31 09:05:37
Yeah, people ARE still talking about rmq even if this bug is the only legacy. Congratulations. :-)
 We Made It
#1205 posted by ijed [190.22.13.160] on 2013/10/31 14:27:25
#1206 posted by gb [46.142.5.157] on 2013/10/31 16:57:11
Heh. =)
=)
#1207 posted by Spirit [80.171.157.235] on 2013/10/31 17:38:31
Honestly though, gb, why bully me?
 Still PVS Mystery
#1208 posted by ALLCAPS [174.106.183.23] on 2013/11/02 04:29:00
I've work on a few other things, like some groundwork for lightmap import, and BSP2 support, but I'm still totally lost on deciphering this PVS information.
C# has a bitarray datatype that would make this really easy to implement if I could just get the PVS data read and decompressed.
I feel like real doofus for asking but does anyone have a page with detailed information on reading and handling the PVS information? I've found so many pages that are just "here's how you do it" with a lump of C source that is a web of pointers, bitshifting, and variables with undescriptive names.
This is the last feature needed before the real fun stuff can begin.
 You're Doing Great
#1209 posted by ijed [190.22.9.14] on 2013/11/02 10:41:34
My only question is will it support bsp2 :>
Sorry, don't have a link for what you're looking for.
#1210 posted by [86.176.34.40] on 2013/11/02 11:01:27
leafs (... leaves ...) contain an arbitary offset into the compressed pvs lump. They don't start at predictable places, and the qbsp is free to overlap duplicate sequences.
Breaking it into 'two byte sets' is thus a silly thing to do.
That said, I have no idea why you would find a 0 0 pair anywhere in the data unless it was unused, which is a possibility.
 Allcaps
#1211 posted by Preach [77.98.165.95] on 2013/11/02 14:28:51
I think you're correct in identifying that the pairs after 7 11 do not parse correctly according to the decompression algorithm. Can you recheck the code that's getting the block of visdata? You may want to check if you get the same data by following the design of the original code more closely: reading each leaf, taking the visdata offset from that leaf, and then reading a pair of chars from that offset.
 Almost
#1212 posted by ALLCAPS [69.34.151.234] on 2013/11/04 04:12:01
Leaf 0's pvs is always "everything is visible". Is this handled as a special case, or does the vis lump contain an entry for leaf 0 as well?
 Almost Almost
#1213 posted by ALLCAPS [69.34.151.234] on 2013/11/04 04:56:14
Okay.
This is the compressed vis data for my testing map.
VisData: (26 bytes) 255 10 255 2 207 10 207 10 243 2 243 2 255 10 255 10 0 1 15 255 15 0 1 7 205 11
I'm inclined to think it's good, because when I use it the level renders correctly. I currently do not decompress the zeros, I can get away with this on my test map because the leafs are so few. Every leaf renders correctly except for 9 and 11, which are the only two leafs to include a zero in their PVS. Fair enough, since I'm not handling the zeros yet. I'm about to, and want to make sure my thinking is correct.
Take leaf 9. It's compressed vis bytes are 0 1. Each leaf takes two bytes of data to have enough bits. After the 0 1 in the data is a 15.
To make sure I'm thinking correctly, this really means it's vis bytes would be 0 15, because it means 0 (starting zero run) 1 (add one zero, done with zero run) 15 (non-zero, add directly).
Is this correct?
 Byte Back
#1214 posted by Preach [77.98.165.95] on 2013/11/04 09:31:25
To make sure I'm thinking correctly, this really means it's vis bytes would be 0 15, because it means 0 (starting zero run) 1 (add one zero, done with zero run) 15 (non-zero, add directly).
Is this correct?
You are correct in how vis leaf 9 works. I think it does expose a problem though.
You started by calculating that each vis leaf requires 2 bytes to store the visibility data of 13 leaves. You then reported that this makes the size of the vis data 26 bytes. The crucial point is that 26 bytes is the size of the uncompressed vis data. We would expect the compressed data to be different in size, otherwise why bother with compression?
To complicate things further, there's an issue of map size. Your map, being unusually small, exposes a rare corner case of the compression algorithm. Leaf 9 has compressed vis data 0 1 15 - that's three bytes. Even if the other 12 leaves lacked zero bytes, that's 12 * 2 bytes + 3 bytes = 27 bytes. The algorithm has made the "compressed" data longer than the uncompressed data!
The important takeaway lesson is that we can't calculate how long the compressed vis data for a map will be from the number of leaves. In most real levels it will be smaller that the uncompressed data, in small box levels it will be larger. The only way to get the correct size is to parse it byte by byte from the file.
 Yes
#1215 posted by ALLCAPS [69.34.151.234] on 2013/11/04 15:32:19
That's what I was doing. Sorry I didn't mean to make it look like I was trying to calculate the size of the compressed data using the number of leafs. It was only by chance that the number of bytes in the compressed data was twice the number of leafs, and that it was two bytes to store the uncompressed pvs for a leaf.
Great to have reassurance though :)
I think I may have it working, it works correctly on my tiny test map, and on Stalwart, a small-ish dm map. Time to get some bigger maps and see what happens.
 Models
#1216 posted by ALLCAPS [69.34.151.234] on 2013/11/04 17:16:56
Alright, I have PVS working for the world itself. How are models other than 0 (the world) handled? Does a leaf's PVS information contain info on every leaf, or just leafs in the same bsp tree/model? It looks like it's just in that leaf's own tree/model.
Are other models just handled via frustum checks?
#1217 posted by Spike [86.178.176.91] on 2013/11/04 19:24:12
pvs is used for 3 things:
bsp rendering (drawing less bsp faces).
entity(net) culling (reducing network traffic).
gamecode logic (trivially skipping tracelines).
the renderer might want to cull submodel faces based upon view position.
or it might batch the entire submodel and be faster if it doesn't then try to split it up.
the other two situations generally use positions relative to the world. submodel pvs information is likely not useful, although it might be handy if both positions are expressed relative to a submodel. such cases are both awkward and minor, as well as infrequent.
phs next? :P
 Process
#1218 posted by ALLCAPS [69.34.151.234] on 2013/11/04 21:14:49
Don't think Quake 1 has PHS, I think Q2 started that :)
My implementation is still a little buggy, due to way I'm handling, or rather not handling, the different models in the .bsp.
Do I need to find the player's position in every model's bsp tree? Right now I find what leaf the player is in starting at node 0, which works but all the non-map models (like doors and elevators and the like) are not marked as visible.
Should my process be to walk the bsp tree for every model? Does each model's head node point to a tree that can be traversed using the .bsp's planes, and end in a leaf for that model? Does this mean there's going to be a set to render for each model in the level?
I was so focused on getting pvs for the map working, I didn't stop to consider what the overall process should be.
#1219 posted by Spike [86.162.117.201] on 2013/11/05 14:42:21
QuakeWorld has phs.
submodels are completely separate objects from the world model. they all have their own separate bsp tree. they just share indexes. node 0 is generally the world's root node, but you'll need to check the submodel lump to find the root node for all the others (and ideally world too).
the view leaf(s) will be different for each submodel, if only because each model has a unique set of leafs.
Either way, translations and rotations would mean you'd need to find the view leaf for each submodel even if they shared leafs.
 Cool
#1220 posted by ALLCAPS [69.34.151.234] on 2013/11/05 15:11:02
That should be simple now that I have methods for vis/pvs and bsp walking going. Good to know I wasn't barking up the wrong tree.
I think I'll actually take a break from this and work on lightmaps. Graphics stuff is more fun. :)
 Another Simple Qc Thing Has Me Stumped
#1221 posted by ijed [200.73.66.2] on 2013/11/08 22:07:05
I've got the tree1.mdl and I'm trying to give it a BBOX size of
setsize(self, '-8 -8 -16', '8 8 96');
But in game the bbox is the size of the entire mesh, which makes it too big to use.
What am I missing here? I've experimented with different collision types and so on and nothing seems to work. Does the mesh itself have some sort of hidden flag forcing this behaviour from qc?
I've got other objects which allow me to manipulate their physical dimensions no problem using the same method...
 Quick Check
#1222 posted by Preach [77.98.165.95] on 2013/11/08 23:37:28
This is probably not the issue, but have you made sure the setsize call happens after you set the model?
 Face Palm That's It
#1223 posted by ijed [190.22.75.99] on 2013/11/09 00:46:01
I was being 'clever' and made a little subroutine to do that for me, leaving it at the end.
So... with that out of the way, if I do this on purpose will the collision be both the right size and orientation?
 Face Palm That's It
#1224 posted by ijed [190.22.75.99] on 2013/11/09 00:46:02
I was being 'clever' and made a little subroutine to do that for me, leaving it at the end.
So... with that out of the way, if I do this on purpose will the collision be both the right size and orientation?
#1225 posted by Spike [31.53.247.81] on 2013/11/09 22:05:21
bbox+bbox collisions fully comply with specified sizes. bbox+bsp collisions have weird offsets+discrete supported sizes.
bbox+bsp collisions are based upon the mins of the bbox rather than the origin of it.
this means you can increase the mins_z to move it up off the ground or decrease it to let droptofloor/walkmove/etc position the base of the tree further into the ground or whatever. it also means you should really try to keep the x+y set to the size of a bsp hull.
if you never use walkmove/droptofloor/tracebox/movetogoal/pushers on your tree then none of that applies and you can set the size to whatever the smeg you want. movetype_none, woo.
 Thanks
#1226 posted by ijed [190.22.86.255] on 2013/11/10 10:27:22
That clarifies things. I've noticed different behavior in different engines as well, but it all seems to come back to not knowing the ins and outs of the format to begin with.
Let's do map objects!
 New Blog Post
#1227 posted by Preach [77.98.165.95] on 2013/12/09 22:05:36
To tie in to the save-game shenanigans from Sunday, here's a blog post describing how to use Preach's black magic for good instead of evil:
Debugging and Save Games
 A Much Sought-After Post
#1228 posted by Preach [77.98.165.95] on 2014/01/03 23:02:04
OK, so it took long enough to debug and make correct that the discussion died down, but here's a post on making ogres play fair and aim vertically:
Proper Ogre Aiming
Hopefully I'm hitting the right balance of maths and code here today, but please tell me if it was too cut-down to comprehend, or waffled too long on the whys and the sums.
 I Suck At Maths.
#1229 posted by FifthElephant [82.24.73.240] on 2014/01/03 23:09:11
...
But I can't wait for someone to compile this so I can get smashed by ogres.
 Aw Snap
#1230 posted by ijed [190.22.78.76] on 2014/01/03 23:22:04
And I just updated their qc in RRP X)
#1231 posted by sock [200.82.43.152] on 2014/01/03 23:27:26
Hopefully I'm hitting the right balance of maths and code here today
Thank you, thank you, thank you! I really can't get my head around all the maths without a good example in QC. This is just perfect for me because I can tweak it and try out different things.
 Also, Bonus Content For Func_
#1232 posted by Preach [77.98.165.95] on 2014/01/04 00:34:39
There are a few places where I made myself leave things out from the QC code as posted, even where the changes are natural and not that hard. This was to maintain the focus on the new idea. Getting gravity correct and moving the launch point of the grenades forward are two such changes that would have distracted; I wouldn't release a mod without them.
The one that I'll share here is how to do the tan function correctly, as you might use it in a maths library. The flaw as I see it is that it changes global state, purely as a side effect, by calling makevectors and overwriting v_forward. It's not hard to imagine how this could break code if users were not aware. Here is the fixed version of tan, which was cut for space:
float(float theta) tan =
{
local vector ang; //temporary used to calculate trig values
local vector v_forward_temp, v_right_temp, v_up_temp;
//save off global state
v_forward_temp = v_forward;
v_right_temp = v_right;
v_up_temp = v_up;
ang = '0 0 0';
ang_y = theta; //assign theta to the yaw to simplify reasoning
makevectors(ang);
theta = v_forward_y / v_forward_x;
//restore the globals
v_forward = v_forward_temp;
v_right = v_right_temp;
v_up = v_up_temp;
return theta;
}
 Zaware Ogres
#1233 posted by sock [200.82.43.152] on 2014/01/06 12:52:22
@Preach, I finally got around to merging your code into my ITS QC base and it works like a charm! Thank you :D
You got a spelling mistake in your tan2 function:
"and = '0 0 0';" should be "ang = '0 0 0';"
Also I highly recommend you prefix your tan/tan2 functions with "mathlib_" otherwise they conflict with the DP extension QC file.
I personally prefer (self.enemy.origin + '0 0 24') otherwise the grenades have a habit of falling short most of the time and especially if the ogre is below the player and close to a ledge.
 Yeah
#1234 posted by ijed [200.73.66.2] on 2014/01/06 13:38:17
Need to get this replacing my dodgy code.
I like your approach, it's the more difficult way of doing it, but intrinsically better.
 Where Can I
#1235 posted by ijed [200.73.66.2] on 2014/01/09 19:28:07
Limit the player's movement speed to walk velocity without changing any cfg values?
#1236 posted by necros [99.227.110.3] on 2014/01/10 03:42:08
you can manually modify .velocity of the player when fl_onground is set. It's not going to be perfect though as there's no way to do this without changing cl_forward/back/side settings.
 Hm
#1237 posted by ijed [200.73.66.2] on 2014/01/10 12:51:05
Ok. My first thought was to just force always run to off, but I know there exist people who don't have that on by default.
But considering what I want to use it for (crippled state) maybe that won't be an issue.
#1238 posted by necros [99.227.110.3] on 2014/01/11 04:58:59
I would modify cl_*speed. Obviously *some* people may actually play with modified move speeds, but I think in your own mod, you have to be able to make some assumptions or decide not to cater to extremes.
 Palette / Wad Question
#1239 posted by Kinn [109.145.163.168] on 2014/01/12 03:26:45
Ok, so I'm writing a tool that reads and writes quake wad files and was wondering if someone knows why some wads include the palette and some don't. Is the palette in the wad used anywhere?
#1240 posted by metlslime [69.181.116.145] on 2014/01/12 04:17:16
gfx.wad probably had the palette in it at one time, before it became a .lmp file instead. Perhaps that is where the palette-in-a-wad came from.
 Right
#1241 posted by Kinn [109.145.163.168] on 2014/01/12 05:28:13
so i should assume the palette in the wad is not used and therefore optional.
 Coding Derper
#1242 posted by ijed [200.73.66.2] on 2014/01/15 20:38:53
So, what does 'Implicit Conversion' mean? I assume it means the result of the IF I'm trying is a constant, but I don't know why this:
if ((self.angles == 90) || (self.angles == 270))
Produces it. Basically if it's been rotated to face north/south as opposed to east/west do X instead of Y. Both of which are bounding box definitions.
Little help? How do I write that IF statement so it's not an Implicit Conversion?
 Is
#1243 posted by ijed [200.73.66.2] on 2014/01/15 20:40:38
angles expecting a '0 0 0' value type?
 I Think Angles Is A Vector Not A Float
#1244 posted by metlslime [159.153.4.50] on 2014/01/15 20:43:12
 So...
#1245 posted by ijed [200.73.66.2] on 2014/01/15 20:53:45
if ((self.angles_y == 90) || (self.angles_y == 270))
Should work?
 Two Alternate Formulations
#1246 posted by Preach [77.98.165.95] on 2014/01/15 20:54:47
if ((self.angles == '0 90 0') || (self.angles == '0 270 0'))
or
if ((self.angles_y == 90) || (self.angles_y == 270))
 Solved
#1247 posted by ijed [200.73.66.2] on 2014/01/15 20:58:27
Thanks guys.
I've been pussy footing around that issue for weeks, if not months now.
#1248 posted by necros [99.227.110.3] on 2014/01/15 21:45:27
Implicit conversion means the compiler is converting a value from one data type to another automatically because you used an assignment operator (=).
Contrast this to explicit conversion where you are telling the compiling exactly what data type you want a value to be. (Note: this isn't possible in QC)
ex:
int x = 10; //32bit integer
long y = 5; //64bit integer
y = x //this is allowed and implicitly converts '10' from a 32bit to a 64bit integer because there is no loss of precision (the number will still be the same).
However, you could not do:
x = y; //because you are trying to move from a 64bit to a 32bit (smaller container) data type. You would have to specifically say you are converting it:
x = (int)y;
What this means in regards to your code is that the compiler was probably implicitly converting '90' into the vector '90 0 0' because going from a float (1x32bit data type) to a vector (3x32bit data types) was not a loss in precision.
Let me know if this is incorrect as it's just my reading of the situation.
#1249 posted by necros [99.227.110.3] on 2014/01/15 21:46:21
sorry, to be specific, it's not just assignment operators, but also comparators ( ==, !=, <, > ). Can't compare apples to oranges!
 Compiler Implicit Conversion
#1250 posted by Preach [77.98.165.95] on 2014/01/15 22:32:54
Although I've got done any careful checking, the bug with the mangle key on...
http://tomeofpreach.wordpress.com/quoth/tutorial/mapobject_custom/
...suggests that it's more common for a compiler to truncate a vector to a float - specifically the first component of the vector.
#1251 posted by spike [86.182.65.134] on 2014/01/15 23:00:07
bad implicit conversions are 'allowed' mostly due to decompilers not being able to determine types properly, and just writing out vec_x as vec instead. such ocde is of course buggy, but should run fine once its recompiled.
c-style casts exist in fteqcc, but are dependant upon opcode extensions or builtins to do the work where the fundamental types are made of different fundamental primitives (ie: floats+vectors are floats, everything else is an int).
qccx-style casts can be achieved with: asm mul_f yoursourcefloat, 1i, yourdestint;
which will rescale your source float and write it as some denormalised float which just happens to match the float's value as an int - so long as its smaller than 1<<23 or whatever it was.
fteqcc does not directly accept (float*1i) because it will convert the int to a float first resulting in no operation, instead of pretending that the int is a float.
note that asm add_f someconststring, 1i, someresult; will return a string omitting the first byte, etc.
hurrah for evil hacks.
ijed, when dealing with angles, I'd be surprised if you could actually get away with comparing exact numbers like that. such things typically need a range tolerance.
 Thanks For The Detail
#1252 posted by ijed [200.73.66.2] on 2014/01/15 23:35:13
It clarifies things for my non-coder mind.
Apples and oranges - got it :)
I'm compiling with fteqcc.
I've got it working now doing the direct comparisons - they've done the trick since I'm looking at a static object placed by the mapper.
A range would be more elegant, but the primitive nature of the mapobjects involved means they should only be rotated 90 degrees anyway - they usually have one or more surfaces that can should be flush to a wall.
And a 45 degree rotation would make baby jesus be shot full of nails ie. cry.
 Jump Tables
#1253 posted by Preach [77.98.165.95] on 2014/01/15 23:46:10
Spike: while you're hear sharing all kinds of wisdom about hacky things involving ints, I've got a question about them.
Is it possible to have a non-constant jump instruction in QC? If that were possible you could create a proper c++ style vtable - have a function which takes a parameter, pass specially designed integer constants for that parameter, and use them to jump to a function call for the "virtual" function the parameter designates. I tried messing around with the asm stuff but the compiler interpreted the variable as a goto label instead. Is this a compiler limitation or something completely impossible in QC?
#1254 posted by Spike [86.182.65.134] on 2014/01/16 04:29:37
there's no such thing as jumptables in QC.
op_if_i, op_ifnot_i, op_goto all take constants only, the offset is directly encoded into the instruction.
on the other hand, op_call* takes a function variable (an index/int).
if you pass a function as an argument, you can theoretically add_f to it to move it on to the next function body defined in the source code, but that's evil.
yeah, a proper c++ style vtable could theoretically be achieved by storing the first function and add_fing an offset to get an indexed function by name... but frankly, I'd just go with fields for them, less hacky then. fteqcc's class stuff already does that, of course.
 Switching Plans
#1255 posted by Preach [77.98.165.95] on 2014/01/16 10:24:41
op_if_i, op_ifnot_i, op_goto all take constants only, the offset is directly encoded into the instruction.
Yeah, this is what scuppers my plan. I basically just wanted a "switch" statement where each "case" calls a virtual function then returns. I think the easiest way to do it now is just use fteqcc arrays, have an array of function pointers, and select/execute the function using an index - which is a bit slower but doesn't need any integer tricks. By having multiple arrays with the same layout for corresponding functions it should be possible to switch between sets.
#1256 posted by Spike [86.135.168.199] on 2014/01/16 14:04:56
struct
{
float(float a) func1;
vector() func2;
float() func3;
} vtable[] =
{
{
class1_func1,
class1_func2,
class1_func3
},
{etc2}, {etc3}, {etc4},
{
class5_func1,
class5_func2,
class5_func3
}
};
idx = bound(0, idx, sizeof(vtable)/sizeof(vtable[0]));
vtable[idx].func1(3);
can do different args that way. all functions from a single class form part of a single struct.
 Quakespy 5.3 (1997)
#1257 posted by Teknoskillz [67.186.168.242] on 2014/01/17 16:52:17
Hi - Didnt know where else to post this here on the site, but was wondering does any one have an old key or registration for the original Quakespy? Not Gamespy, but just Quakespy. I have asked Gamespy if they would release the old src to the public but never got an answer....
 A Random Article
#1258 posted by Preach [77.98.165.95] on 2014/01/23 02:26:06
It was nice to get so much positive feedback for the ogre article, I'll try and do more like it in the future. I think it was helped by being reasonably timely about an interesting open problem - so keep generating those kinds of ideas for me to tackle :-p
Today I'm polishing up an article I started in October, and it's on the maths-heavy side. In UK secondary schools you typically take one of two routes when studying Maths to age 18. Some students take on modules in Mechanics, and they would be well placed to tackle the grenade article from last time. The other route is Statistics, and so here's an article for them instead!
http://tomeofpreach.wordpress.com/2014/01/23/removing-busy-random-polling/
I've tried to push the heavy maths parts onto links again, but I do spend some time in the middle justifying the core idea. It's an older article and I spent too long on the graphs to delete them, so just feel free to skip that chunk. Also if you get the feeling at the start that this is unnecessary optimisation, make sure you catch the better reasons to do it near the end!
 High Plane Maths
#1259 posted by sock [200.45.126.26] on 2014/01/23 13:00:16
I am not really sure how I can use this for anything, I don't have any functions that do what you are optimizing. Sorry, this article feels too abstract and more for you than anyone else.
If you want ideas for future code articles what about, creating ladders, tracking missiles (quoth rocket guy), vertical movement code (quoth bob), or improving the fiend jumping mechanic.
 How About Enemies
#1260 posted by FifthElephant [213.205.234.180] on 2014/01/23 14:21:50
That are set up with proper pathing? Like in unreal?
 Pathfinding
#1261 posted by Kinn [80.247.24.248] on 2014/01/23 14:33:27
you'd need to write an a-star algorithm in QC and lay down a veritable shitbiscuit of triggers to acts as nodes.
It's not a great language to do that in tbh but i think it's been done in the past.
 Why Not Use Path Corner?
#1262 posted by FifthElephant [213.205.234.180] on 2014/01/23 14:36:18
Wouldn't that work?
 FBX Waypoints
#1263 posted by onetruepurple [91.240.47.30] on 2014/01/23 14:38:08
 The Point Is
#1264 posted by Kinn [80.247.24.248] on 2014/01/23 14:39:01
you need to write the underlying system that dynamically creates the sequence of path-corners the monster needs to follow to get from where he is to his goal.
 Lost In Translation
#1265 posted by Kinn [80.247.24.248] on 2014/01/23 14:40:48
when i said "trigger" i meant whatever entity you create to represent your a-star node.
 AI Pathing
#1266 posted by sock [200.45.126.26] on 2014/01/23 14:48:47
It's not a great language to do that in tbh but i think it's been done in the past.
Did you play my ITS mod? I wrote an Article on what AI system I wrote in QC and how it works, ingame/editor shots as well!
 That's Pretty Cool, Yeah
#1267 posted by Kinn [80.247.24.248] on 2014/01/23 14:53:59
I was talking more about this stuff: http://en.wikipedia.org/wiki/A*_search_algorithm
Your system looks pretty hand-placed but if it works for basic quakery, then it's all good :}
 Different Strokes
#1268 posted by sock [200.45.126.26] on 2014/01/23 15:33:01
Necros did a similar system with nodes, generating best paths from node networks and then setting the AI on that path. The problem with that system is, it can be CPU intense to generate the path every time (especially vertical complex levels) and if anything changes (player / environment) it becomes out of date quickly.
I personally elected for a dynamic system, the AI knows where it wants to go (final objective) but trusts the node network to reach there. The AI find the nearest node, finds the best direction and then starts following the network.
As the final destination (player) keeps moving the AI keeps adapting using the node network. The minor navigation (around rooms) is left to the node network while the high level signposts stuff is done via volume brushes.
Its not perfect but it does cope with fairly well with moving objectives (player) and even gets the AI back to what they were doing before.
The downside is the node network has to be hand placed and the network has to be validated / connected together when the map loads.
 Repost
#1269 posted by ijed [200.73.66.2] on 2014/01/23 16:10:03
This is an interesting read on making a dynamic system that follows simple empirical rules.
https://www.quaddicted.com/webarchive/minion.planetquake.gamespy.com/tutorial/main.htm
 Btw
#1270 posted by Kinn [86.145.179.85] on 2014/01/24 02:10:36
A word about A* pathfinding being cpu-intensive... I've coded a couple of A* systems for games in the past, and if you can create a sort of heirarchical A*, it's incredibly fast (basically you do pathfinding on a heirarchy of graphs, starting from the coarsest and working down - e.g. "region nodes", then "room nodes", then "nav-tri nodes")
e.g. once you get down to the point where you need a path between individual navtris, you only have to find a navtri path between nodes on the next graph up (e.g. just between adjacent room nodes)
This already makes it blazingly fast, but you can still get spikes if you need lots of paths all at once (e.g. lots of monsters all going at it) - I handle this by amortising the algorithm over several frames and also queueing up requests, so they are processed for each monster in a linear fashion. The upshot of it all is basically no performance impact whatsoever.
The creatures have simple fallback behaviours that they can do whilst waiting for their paths to be processed, but I find the delay is so small it's never noticeable.
But, yeah I wouldn't wanna do it in QC...
 Sounds Like
#1271 posted by ijed [186.79.193.53] on 2014/01/24 02:50:23
Navmesh. I haven't personally implemented this before, but have worked with it quite a bit.
As I've seen it throws voxels at a map and creates polys where possible. The quake equivalent tech is probably the vis process, with leafs instead of polys.
Ai navigates between the polys, path finding to their ideal destination.
Incredibly slick system, works amazingly well. They used a terribly shitty version of this in L4D... We analyzed it and it was puzzling why it was so bad, when we stole ours from an online tutorial and it worked like a charm.
I suppose they were worried about more important things though, like not making a game that sucked. Our game sucked, but I'm not going to say which it was since it got universally panned.
All this makes me wonder if a similar approach could be applied to the vis data though, using ray casts or something to construct chains. Wouldn't work for areas that monsters can't navigate though, like vertical drops and the like.
Detail brushes would also cause problems.
 It's A Navmesh System Yes
#1272 posted by Kinn [86.145.179.85] on 2014/01/24 03:15:03
Also you make an interesting point with vis connectivity.
One thing I've been meaning to do is dig around to see how the doom3 AAS is generated - that's another system where the graph is created procedurally with almost no work from the designer required...
#1273 posted by necros [99.227.110.3] on 2014/01/25 06:32:28
I handle this by amortising the algorithm over several frames and also queueing up requests, so they are processed for each monster in a linear fashion. The upshot of it all is basically no performance impact whatsoever.
I've had to do this as well; ne_ruins didn't have it though.
Deferring the path solution over multiple frames works very well and I remember testing giant horde maps with a hundred monsters all able to path without any slowdown at all. The only downside is that the more monsters there are, the longer it can take for each AI to have it's turn at getting a path generated for it.
The last optimization that I have yet to implement is having a monster save a generated path.
As it is now, I regen a path every time an AI hits the node it was heading towards. This is pretty expensive, especially in node-dense areas. If an AI could get a path generated and remember not just the next node, but all the nodes that make up that path, it could treat it's A* path like a series of path_corners and be very cheap to run.
#1274 posted by sock [200.45.126.26] on 2014/01/25 11:43:13
But, yeah I wouldn't wanna do it in QC...
In hindsight it was a crazy idea, but I did learn a load of things about AI. When I finally got the Quake monsters to path around a map avoiding obstacles and hunting the player it was an awesome feeling of accomplishment.
I did look at necros QC but soon realized I was going to struggle with the idea, I am designer not a coder. In the end I decided to go with a simple path node system (like in heretic2) with some extra helper options (jump, shoot, path choice) so that the AI can look intelligent when the player is around. I even wrote a ton of debug modes for tracking down errors in the pathing routines so it was easy to find out where things were going wrong.
 When I Saw ITS
#1275 posted by ijed [190.22.27.77] on 2014/01/25 12:11:18
I assumed you'd used the frikbot code, since the behavior was so similar in many respects.
One rainy day I'll dive into that and see how to link it into the monster ai.
It almost never rains in Chile. There are more earthquakes than storms.
#1276 posted by sock [200.45.126.26] on 2014/01/25 12:24:05
I assumed you'd used the frikbot code
A couple of people said this to me, but I did not look at the Frikbot code, because I assumed it was a new engine. The problem I found with implementing AI changes is you can end up replacing so much of the underlying QC that it is often difficult to integrate into existing progs.
 I Think
#1277 posted by ijed [190.22.27.77] on 2014/01/25 12:43:51
This is what happens when you first attempt it. Once you've got a handle on things you start to make ai changes that work in tandem with what's in the original game.
One of my favourite bits of code is the additions to trigger_monsterjump; only enraged and only melee. Basically an idea stolen from the Quoth drolejump, that have proved incredibly useful.
I've been throwing around ideas for trigger_alarm and trigger_guard, also for a special type of path corner that would override the monster's move goal during combat. Basically conditional things that you place when mapping to provoke behaviour that fits your level.
Crude stuff compared to a node system, but I've seen promising results from some of these ideas so far, just because they're level customized rather than 100% generalized.
 NecroStar
#1278 posted by Kinn [81.156.206.160] on 2014/01/25 13:31:06
The last optimization that I have yet to implement is having a monster save a generated path.
As it is now, I regen a path every time an AI hits the node it was heading towards. This is pretty expensive, especially in node-dense areas. If an AI could get a path generated and remember not just the next node, but all the nodes that make up that path, it could treat it's A* path like a series of path_corners and be very cheap to run.
This is probably the main reason I wouldn't wanna do it in QC. In QC each generated path would be a linked list of entities I imagine - and there'd be huge amount of them if each monster had his own set.
Could be worth looking at heirarchical pathfinding, where you have seperate graphs at different scales. e.g. let's say your map is divided into 5 broad regions. These are your highest level nodes, and you start by creating a path through these region nodes. Now, starting from the region the monster is in, you know which adjacent region you need to head towards, but to get from region to region you need to navigate a more detailed graph, made of say "room nodes", but because at any one time, you are only ever concerned with navigating into an adjacent region node, you only need to consider the room nodes in your current region, which clamps the max. number of room nodes in this next path to a pretty manageable number. Then once you need to navigate from room-room, you might still need a more detailed graph using another type of sub-node (each room would have several of these), but again you only need to consider just those sub-nodes in the room you are in to lead to the next room....
I hope that makes sense.
The upshot of it all is that it massively, massively reduces the number of pathnodes you'll need to process and store at any one time.
 Alternative Universe
#1279 posted by sock [200.45.126.26] on 2014/01/25 14:44:12
Could be worth looking at heirarchical pathfinding, where you have seperate graphs at different scales.
This is essentially what I am doing with my node network except I am using a terminology which is probably misleading. I essentially create a series of large brush entities and when the client starts, I store their volume bounds, reduce them down to a point entity and make sure they are non interactive with the world.
I generally create a loop of nodes in a room linking all the doorways. I then place special volume test entities on top of the nodes and link them together. When an AI arrives at a node it does a simple bounds/volume test on the final destination and if correct goes through the doorway on to the next set of nodes.
It is really easy to cut up a level into 5-10 volumes and being as they are visual in the editor it is easy to place them as a LD. I even added and/or/not logic to the volumes so AI can test several volumes together for a much better test of destination.
Once you've got a handle on things you start to make ai changes that work in tandem with what's in the original game.
The problem is the original game AI design is terrible, they essential run in a straight line bouncing off architecture in order to find their way. It is extremely easy to create architecture that breaks this and essentially the player is just shooting fish in a barrel as the AI run endlessly trapped on ledges or round in circles in lower areas of rooms.
Most Level Designers for Quake compensate for this AI flaw by using range/flying units which evens out the playing field for the monsters.
 Cool Stuff
#1280 posted by Kinn [81.156.206.160] on 2014/01/25 16:00:28
I did some last-ditch bodges in my (released) quake maps where I identified some areas in the game where monsters got stuck, like in spiral stairwells and stuff, and added some path corners leading out of there and logic that said things like "if player is above you follow path forwards, else follow path backwards".
Stepping back for a bit, my opinions on pathfinding in Quake have been a bit back and forth over the years. I've always leaned towards just leaving the AI alone. I think one of the things with Quake is that monsters are so aggressive that it actually works to the game's advantage that they are a bit shit at chasing the player. Typically when you have an encounter, you want the option to back out of it and not have the monster chomping at your heels the whole time. Sometimes they chase you, sometimes they don't, and I like that.
#1281 posted by sock [200.45.126.26] on 2014/01/25 16:09:53
I've always leaned towards just leaving the AI alone. I think one of the things with Quake is that monsters are so aggressive that it actually works to the game's advantage that they are a bit shit at chasing the player
My mod needed the AI to hunt the player down, it would have been a very poor stealth game if the AI could not even exit a room or get back to what they were doing before. I can see the attraction of Quake AI being left alone, they are easy to break, but when a monster does something (eg monster_jump) surprising like hunting you down, then it gets more exciting! (well for me)
 Same
#1282 posted by ijed [190.22.27.77] on 2014/01/25 19:23:07
I like them to do cleverer stuff, although it's tricky to do it without also giving them super powers.
Like the aiming ogres that added speed to their grenades in order to hit the player.
#1283 posted by necros [99.227.110.3] on 2014/01/25 20:25:44
The problem I found with implementing AI changes is you can end up replacing so much of the underlying QC that it is often difficult to integrate into existing progs.
Yes, this is the really unfortunate part. I've been trying to write a simple tutorial where I could provide the main A* component and then someone could just go in and hook it into their mod, but there are so many little bits that have to be added and so much that is flat out replaced that it's not simple at all to write the tutorial. :\
Sock: Your method is very cool, but I find it is really fiddly with adding in the nodes because you have to tweak it for each area. The results are better but it's more work and I am super lazy: I prefer just throwing down nodes and letting the code sort itself out!
Kinn: I have considered doing the coarse graph -> fine graph approach. For some reason, using a large brush and auto-linking them the way Sock is doing never occurred to me and I always assumed I'd have to do a lot of manual linking which is why I never bothered... This is worth some more thought, I think.
Also, yes I have some utility functions that make linked lists, queues and stacks out of entities. There is a queue of entities that tracks which monster is next to get a path generated, for example.
If you're using fitzquake or a variant, it's less of a problem since you have up to 32000(?) entities to play with and since they have no models attached to them, they don't actually cause overflows or anything.
 Containification
#1284 posted by Preach [77.98.165.95] on 2014/01/26 00:23:26
Also, yes I have some utility functions that make linked lists, queues and stacks out of entities.
This is something I was also considering for a series of tutorials - I have a nice way to make generic "container" functions using a trick with field pointers. Maybe I'll start on that next...
#1285 posted by Spike [86.183.24.106] on 2014/01/26 03:14:59
If you want to do routing properly, you really ought to do it on another thread - that means some engine extension to do it.
That said, doing it in the engine has certain issues, including not knowing what a teleporter is.
#1286 posted by necros [99.227.110.3] on 2014/01/26 03:35:52
Teleporters aren't too bad. If your system allows for manual linking, you simply link nodes between both sides and sit them inside the teleport trigger.
Doing it in the engine though, that'd be pretty nice, but if you're going that far, you may as well get compiler support and make AAS files. I was really impressed with the D3 AAS generation.
 Less Is More
#1287 posted by sock [200.45.126.26] on 2014/01/26 13:58:06
Your method is very cool, but I find it is really fiddly with adding in the nodes because you have to tweak it for each area. The results are better but it's more work and I am super lazy: I prefer just throwing down nodes and letting the code sort itself out!
Yeah that is the downside to manual node layouts, but it is not really that much work because you can added/updated the nodes using -onlyent compiles. I also found that less nodes often produces better results than trying to saturate an area with complex setups.
Here is the numbers for my two test maps:
S1M1 - 123 Nodes, 61 Vol Nodes, 23 Volumes
S1M2 - 129 Nodes, 67 Vol Nodes, 15 Volumes
The volume nodes are linked to the nodes, they are the high pass route choices. The volumes are brushes defining zones to the map for nodes.
I am still a firm believer that manually designed routes produce more robust results and with the right debug options you can easily find problems and fix them. Which is why I spent so long creating them. You can drop down start and destination markers, work out which nodes to go to first (pretend you are the AI) and then follow the path through the node network visually.
If you want to do routing properly, you really ought to do it on another thread - that means some engine extension to do it.
That said, doing it in the engine has certain issues, including not knowing what a teleporter is.
That would indeed be awesome but based on my experience of Quake engine devs there would probably be 3 different formats not compatible with each other and LDs wondering which format to work with! ;)
The hardest part of node networks for me is lift/platforms because the AI has to wait for platforms, get on them correctly, wait on the platform and then get off. Pausing AI and switching them between stationary and mobile is awkward with the current QC structure.
 Cannot Agree More...
#1288 posted by FifthElephant [82.24.73.240] on 2014/01/26 14:46:23
"I am still a firm believer that manually designed routes produce more robust results"
Coming from a UT mapping background originally I can honestly say once you got a nice path network going and you followed a bot that could navigate your map properly it was a great feeling of satisfaction.
I envy what Polge did for UT, it's a shame that he didn't flesh out his Reaper Bots for quake a little more. :)
 Is There
#1289 posted by ijed [200.73.66.2] on 2014/01/28 22:49:20
A maximum number of entities that can be searched through with the find function?
I'm using it to search through randomiser entities and it seems to be provoking a crash now, as the map and number of entities has grown in size.
#1290 posted by necros [99.227.110.3] on 2014/01/28 23:08:05
it's possibly you're hitting the 100,000(?) operations per frame limit.
In a given frame, you can do 100000 operations before the engine thinks you're stuck in an infinite loop. This includes all operations done before you hit your loop and all the operations done after your loop, so you can get through your loop fine only to crash on subsequent operations done after.
the solution to this is to defer the search after n loops to the next frame by saving the last entity and starting from there instead of world.
 Sounds About Right
#1291 posted by ijed [200.73.66.2] on 2014/01/29 00:01:06
Just talking with Sock about it.
I threw in some delays and it certainly seems to be the case. The size of the map is basically breaking this limit.
What I'm doing is randomising monster position, and the code I'm using is searching the entire entity list to do so.
If I chained the entities it'd work much better, but that's a massive amount of work.
Not using randomisation would have the benefit of more precise monster placement and not having to rewrite the code and map.
Just delete a load of entities from the map.
Thanks, seems like the way ahead is clear!
I could rewrite, but it'd take a lot of time. In future projects I can take this limitation into mind and use stuff which has nextthink = time + random(); or similar.
 So
#1292 posted by ijed [200.73.66.2] on 2014/01/29 15:11:48
I'm removing all the randomiser entities and replacing the monsters traditionally.
This'll give me a playable level.
I've got in mind a randomiser system that would be supported by the single thread engines that Quake uses.
Basically it flagging monsters as RANDOMISED (additional to the SPAWN_SILENT, SPAWNED and SPAWN_ANGRY flags).
Each monster would have keys to denote their randomiser grouping. These keys would be rname, rnext and pool.
rname and rnext would copy the door code to produce chain grouping. This would make things much lighter when using the find function. Erroneously configured chains would have a failsafe to make sure they'd always be a loop.
All monsters in the same group would randomise their positions between the others in the group, any monster ending up in another position would also inherit the target of that position (to point at the relevant path_corner or trigger_counter) if a monster didn't have a target then this would clean any target held by the arriving monster. The difficulty flags and targetnames would remain unchanged.
Monsters with pool set to 1 would never add the position etc. to the randomisation group, but could take the place of other monsters. Possibly there'd be other functionality for pool, which is why it should be a key and not a flag.
Basically this means that the monsters not set to pool 1 define the positions used for spawning and how many monsters will be spawned.
Monsters would only be randomised when spawned, so quick loading after dying would re-randomise the monster positions as they would be retriggered.
This would produce a system optimal for the engine and simple for the mapper, even though it involves a flag and three separate keys.
Probably won't do it in this project though. Maybe next time.
 Pool 2
#1293 posted by ijed [200.73.66.2] on 2014/01/29 15:33:17
This would make a monster not spawn. The utility would be placing three shamblers for example, but only one appears.
 Uh
#1294 posted by ijed [186.9.132.84] on 2014/01/29 17:12:46
I mean, pool 2 would make a monster part of the group, but not increase the amount of spawns for that group.
 QuakeC IDE
#1295 posted by Kinn [109.145.165.230] on 2014/02/08 00:27:06
So apparently you can use "Code::Blocks" as an IDE for QuakeC, with autocomplete and all that shizzle.
Anyone use this? I followed the instructions here: http://ouns.nexuizninjaz.com/dev:programming_introduction#working_with_the_code
But I can't get the pissing thing to work properly - my symbols tab is empty and it can't find any of my functions or do autocomplete or any of the things which would make it better than, you know, notepad.
Has anyone else got it working for QuakeC?
 Hmm
#1296 posted by Preach [77.98.165.95] on 2014/02/08 01:07:41
Gave it a try, but I don't know the first thing to do with codeblocks, so didn't get very far.
Did notice that the lexer_qc.xml file has a bunch of typos in the keywords though, so it's not going to be highlighting .vector, continue or default any time soon...
 Yeah
#1297 posted by Kinn [109.145.165.230] on 2014/02/08 01:52:56
I noticed all those typos too. Doesn't fill me with much confidence to be honest.
 Dyslexer_qc.xml
#1298 posted by Kinn [109.145.165.230] on 2014/02/08 01:55:59
more like lol
 Some C++ Help?
#1299 posted by necros [99.227.110.3] on 2014/02/08 02:58:52
Coming from Java, this C++ stuff is confusing to me...
I have this class which is meant to be an Interface:
class PhysObject
{
public:
virtual void evaluatePhysics() = 0;
protected:
Vec2 velocity; //physicalized objects have velocity
PhysObject() :
velocity(Vec2())
{}
};
Then I have this other class that implements PhysObject:
class Particle : public PhysObject
{
public:
Particle(Vec2 pos) :
position(pos),
size(Vec2(4, 4)),
releaseTime(Game::Time() + 1),
PhysObject()
{}
void evaluatePhysics()
{
this->position = this->position + (this->velocity * Game::FrameTime());
}
...
};
But when I call this->evaluatePhysics() on the Particle object, it crashes with access violation 0xCDCDCDCD which the internet tells me is caused by dereferencing a null pointer. So it looks like my evaluatePhysics() implementation in Particle never actually took, and it's still trying to call the Interface's evaluatePhysics() = 0 pointer.
Any hints?
#1300 posted by ericw [172.219.249.35] on 2014/02/08 03:45:43
I think you just need to add 'virtual' before 'void evaluatePhysics()' in Particle.
Also, sounds like there's a new c++11 feature where you can stick the "override" keyword after the function args in Particle, like this:
virtual void evaluatePhysics() override
{
which will make the compiler check that this evaluatePhysics() is actually overriding something from the parent class.
#1301 posted by necros [99.227.110.3] on 2014/02/08 05:23:57
no dice, neither from adding virtual or override. :(
From what I've read, once you put virtual on a method, everything from that point forward will always be virtual, ie: behave as expected of a polymorphic object and properly call child class methods if held in a base class container.
#1302 posted by ericw [172.219.249.35] on 2014/02/08 06:18:30
ah, you're right - sorry for the bad advice! the setup of evaluatePhysics() looks fine to me then.
all I can think of is generic debugging advice.. like, stick a:
printf("inside Particle::evaluatePhysics()\n");
at the first line of evaluatePhysics(). double check the particle object you're calling ->evaluatePhysics() on is not NULL. is it possible Game::FrameTime() is dereferencing a null pointer?
it should be possible to get a debugger to break when a null pointer dereference happens, so you can look at the call stack and ideally see exactly where the problem is. which IDE/environment are you using?
 Test Case
#1303 posted by Preach [77.98.165.95] on 2014/02/08 10:04:30
Here's my very reduced test case
http://ideone.com/u1scWv
I actually put an implementation in my base class but it's easy to check that it works when it's pure virtual. Anyway, it's all got the same syntax and setup as your code above, so there's a detail wrong somewhere.
Have you tried putting a dummy evaluatePhysics function in PhysObject for debugging purposes. Just a quick one-liner that maybe logs a message. It would be a quick way to test if it is the "pure virtual" function which is causing the null pointer dereference.
#1304 posted by necros [99.227.110.3] on 2014/02/08 16:28:54
Nothing changes when I implement evaluatePhysics in PhysObject, so something else must be going wrong here.
debug on particle object: http://tinypic.com/r/ibctq9/8
There's a __vfptr member at 0xCDCDCDCD?
Here's the entire Particle class:
http://pastebin.com/jmtfPHs3
static void drawParticles() is called each frame which in turn calls this->evaluatePhysics() on any living particle.
 Self.items Bugs
#1305 posted by Qmaster [50.40.219.151] on 2014/02/08 19:37:49
Can anyone explain to me what the limit is on numbers that I can store in self.items, and how it works? I've been having some very odd bugs with my mod. I have 16 different weapons, but for some reason I'm getting wierd errors where certain weapons are already owned, getting ammo gives the weapon, etc. etc. I'm thinking that perhaps there is a limit on how high the number can be for IT_<WEAPON NAME HERE> in the defs.qc. Is 16777216 too high a number to even fit in the float variable self.items?
I understand that certain numbers are assigned in a bitwise fashion for the correct HUD art to display, but I think I'm misunderstanding how it all works.
 Append To Previous Post...
#1306 posted by necros [99.227.110.3] on 2014/02/08 19:42:44
cleaned up the code I posted above:
http://pastebin.com/hAXRXryT
 Qmaster
#1307 posted by necros [99.227.110.3] on 2014/02/08 19:44:43
highest number you can use for any number in qc: 8388608
#1308 posted by necros [99.227.110.3] on 2014/02/08 19:45:06
highest flag you can use, sorry. :(
 Trial And Error With IT_ Numbers
#1309 posted by Qmaster [50.40.219.151] on 2014/02/08 20:31:11
Still hammering out (inside joke/pun!) the problems with IT_ numbers (1,2,4,8,16,32,etc.,4096,8192,etc). Apparently there is some engine code to handle the numbers stored in self.items, because otherwise picking up one item with a completely different touch function from another wouldn't still play that item's pickup sound. Apparently the engine is looking for a sum??(help!?) of the items contained??
#1310 posted by necros [99.227.110.3] on 2014/02/08 20:50:20
so the way items works is that each IT_ value corresponds to a bit.
in binary,
1 is 0000000000001
2 is 0000000000010
4 is 0000000000100
etc...
storing items this way is a compact way of storing a bunch of yes/no settings in one spot.
if you do items = items | 4 you are essentially setting bit #3 to on. if it was already on, nothing happens.
so if you have multiple items stored on items, if you were to print it, you might see '7'
but actually what it is is: 0000000000111
so it means bits 1, 2 and 3 are 'on', in other words if you had:
IT_GUN1 = 1
IT_GUN2 = 2
IT_GUN3 = 4
it would mean you had all 3 guns in your inventory.
 @necros
#1311 posted by ericw [172.219.249.35] on 2014/02/08 20:52:44
I think i see the problem, it's cause by allocating memory with malloc, and then copying the particle in.
Here's a reduced test case that segfaults on the line particle->evaluatePhysics();:
http://pastebin.com/WB7iVHP1
I can't find a great explanation of why this is illegal. there is some stuff here: http://www.drdobbs.com/cpp/calling-constructors-with-placement-new/232901023?pgno=1
To fix it, I'd replace this:
Particle* Particle::pool = (Particle*)malloc(sizeof(Particle) * Particle::MAX_PARTICLES);
with an std::vector<Particle> Particle::pool;.
generally, you should avoid malloc in a c++ program and use new/delete, and the STL containers.
hope this helps :)
 Thanks!
#1312 posted by necros [99.227.110.3] on 2014/02/08 21:51:35
That seems to be exactly what the problem was! I had used a static array because I planned to never grow it in size, but didn't know that it had trouble handling polymorphic stuff. Guess I shall stay away from malloc from now on.
 @necros
#1313 posted by Qmaster [70.195.64.41] on 2014/02/08 22:17:50
That makes so much sense now! Thank you! So this means that a standard quake integer (read that the float is floored) would initiate to 0000000000000000000000000000000 (32 0's) since it's 32bit, right? So I could have a total of 32 weapons then right?
 Qmaster
#1314 posted by Preach [77.98.165.95] on 2014/02/08 22:30:41
Unfortunately not. QC doesn't let you use integers, but floats. A 32 bit float only dedicates 24 bits to "places" in the number, the rest tell you the sign and the "scale" of the number. Basically when the number is large enough a float can't store integers accurately - the largest whole number that can be safely stored without rounding is 16777215. That's why necros gave 8388608 as the maximum size.
It is possible to use the non-place bits in a floating point value for more flags, but it's really incredibly fiddly. Better to just add another field to the entity and store the extra flags there.
re: pickup sounds. These are all specified in items.qc - the sound is based on the classname of the entity you touch.
 16777216
#1315 posted by Qmaster [70.195.64.41] on 2014/02/08 22:51:51
http://dev.xonotic.org/projects/3/wiki/Introduction_to_QuakeC
float
This is the basic numeric type in QuakeC. It represents the standard 32bit floating point type as known from C. It has 23 bits of mantissa, 8 bits of exponent, and one sign bit. The numeric range goes from about 1.175e-38 to about 3.403e+38, and the number of significant decimal digits is about six.
As float has 23 bits of mantissa, it can also be used to safely represent integers in the range from -16777216 to 16777216. 16777217 is the first integer float can not represent.
 Oh Didnt See @Preach's Post
#1316 posted by Qmaster [70.195.64.41] on 2014/02/08 22:58:20
So that explains why I've had so many issues with the weapon assigned to the last bit slot of 16777216. Good to know that 8388608 is max. Phew, adding more weapons is gonna be a bit tricky then.
#1317 posted by necros [99.227.110.3] on 2014/02/08 23:54:32
the way floating point numbers are stored is actually pretty cool. it allows for a huge amount of scaling at the expense of precision.
 !
#1318 posted by Qmaster [50.40.201.119] on 2014/02/19 04:07:34
BUMP!!
Can we please sticky this thread next to Mapping Help? I come here often to read up on awesome stuff going on in QC Land but I keep having to dig down in All Threads.
#1319 posted by necros [99.227.110.3] on 2014/03/23 03:51:21
is there a reason why C++ compilers are so unhelpful?
the language is nice and having access to the heap and more control over what goes on the stack is great but tracking down some bugs or even mistyped things can be such a hassle.
 Clang
#1320 posted by Preach [77.98.165.95] on 2014/03/23 06:44:33
I've not used it myself, but one of the touted features of the clang compiler is superior error message delivery:
http://clang.llvm.org/diagnostics.html
Might be worth a punt...
 Hah
#1321 posted by SleepwalkR [85.178.58.1] on 2014/03/23 09:35:29
The problem with C++ error messages is (nested) templates. This makes the error messages very long and basically unreadable. The Xcode IDE is quite helpful here because it allows you to click on the separate lines of a template error and highlight their occurrence in the source files.
Other than that, I remember reading a trick to simplify the error messages in a C++ book. I can look it up if you're interested.
Preach, maybe clang has better error messages than others, but they're still hard to understand when there are templates involved ;-)
#1322 posted by mwh [2.29.231.193] on 2014/03/23 10:31:34
#1323 posted by JneeraZ [108.228.244.211] on 2014/03/23 14:16:55
#1324 posted by necros [99.227.110.3] on 2014/03/23 16:36:59
lol willem, yeah, i feel like that sometimes. :)
as for using another compiler, i have no idea how to change it since i'm using visual studio 2012... i assume i'm just using microsoft compilers of some kind.
 Cpp
#1325 posted by necros [99.227.110.3] on 2014/03/23 21:09:57
to give an example, at one point i started getting an error saying NULL was an undefined variable. and then suddenly it went away and I have no idea what caused that to happen.
 Yes
#1326 posted by SleepwalkR [92.231.104.140] on 2014/03/23 23:25:15
NULL is a typedef for the literal value 0. It is defined as soon as you import any STL header, such as iostream.
#1327 posted by necros [99.227.110.3] on 2014/03/23 23:45:03
yeah that's what i mean. it should just be there regardless but something i wrote in my own code was stopping it from being defined or at least, made it look that way to the compiler.
i'm sure if i knew more about it it wouldn't be that strange but for a noob like me, it's just befuddling.
 New Blogosphere
#1328 posted by Preach [77.98.165.95] on 2014/05/12 00:31:17
So I haven't posted much on the old blog this year - putting together the Quoth release took up most of my Quaking time. So now that it's out the door, here's a return to posting stuff. Today we develop a bit of a hack to create an EndFrame function.
http://tomeofpreach.wordpress.com/2014/05/11/creating-the-endframe-function/
There are a bunch of extra hacky things this makes possible, but the article is tightly focused, maybe I can follow up with some of the options...
 @Preach - Entity Order
#1329 posted by Qmaster [50.40.172.162] on 2014/05/17 03:34:28
Does this mean there's a way to reorder the entity edicts list? Is that what .chain and head are doing? Care to explain how those work, please?
I have a really cool entity that requires any linked entities to be right next to each other (or very nearly) in the edict list in order to avoid any mid-frame lag between eachother. I haven't released the entity as a standalone .qc file yet since I haven't found a workaround for telling people to "Yeah, just select the entities in the editor, copy them, delete them, then paste them to bring them back, then compile. That way the linked entities are always last on the edicts list since they are last in the map file. That way you avoid any mid-frame lag from having to calculate too many physics calls in between entities within the same frame." (DEATH to 0.100 second delays when arriving at path_corners!)
Is there a way to always make sure these entities are near each other in the edicts list so that they're physics are called together?
#1330 posted by necros [99.227.110.3] on 2014/05/17 03:39:21
.chain is set when you run findradius. the engine simply sets this on all entities in the radius so you can iterate through them.
relying on the entity spawn order for your code is dangerous and impractical. it would be better to create a new .entity field and then build your list of entities with the new field at map start once. then you can iterate smoothly without having to rely on the map playing nice.
#1331 posted by Spike [86.169.38.140] on 2014/05/17 08:25:04
@Qmaster: try using copyentity to copy the slave entity towards the end of the list. combine with the entnum builtin/intrinsic/nextent so you know the order is okay. do it inside the master's spawn function if the slave already exists and you should be okay with respect to targetname stuff on other entities.
 Agreed
#1332 posted by Preach [77.98.165.95] on 2014/05/17 08:53:14
Now, from the context clues in your post, I'm guessing you're trying to create some kind of escalator or conveyor belt contraption out of a set of func_train entities. Ensuring that all of the trains are next to each other in the entity list will not save you here. One way they can still go out of sync is if a player blocks one of the trains, but the others are free to move.
What I'd recommend is getting a copy of the "custents" mod, and looking at their func_train_sync entity, which is designed to fix this specific issue. I can't remember if the fix was complex - like ensuring all the movement shuts down when one entity is blocked, or the simpler solution of having individual entities wait at each corner until all the trains have reached their next stop.
 ...btw
#1333 posted by Preach [77.98.165.95] on 2014/05/17 11:01:18
Incidentally I'm running into a bug now with the tutorial I posted, so hold on using it until I figure out what's causing it. It's the kind of bug that creates a substring out of a QC string, so something's really having a party on the entity...
 Fixing Endframe
#1334 posted by Preach [77.98.165.95] on 2014/05/20 23:27:32
Ok, so it turns out that the compiler optimisations I was using with FTEQCC have an obscure bug that got exposed by the spawn() function wrapper in the previous tutorial. This was corrupting the entities, and it also managed to corrupt the linked list in CreateBackstop to obscure the fact that it should loop infinitely.
The full skinny on what form the bug takes, how to work around it, and how to fix the bugs it masked in my own code is now up on the blog:
http://tomeofpreach.wordpress.com/2014/05/20/fixing-the-endframe-function/
 @Preach
#1335 posted by Spike [86.169.38.140] on 2014/05/21 01:03:34
Preach, in all seriousness, get an updated version. That's an order!
 New Release?
#1336 posted by Preach [77.98.165.95] on 2014/05/21 09:21:54
Latest version on the page is 1.0 and that's like 3 years old...
#1337 posted by Spike [86.169.38.140] on 2014/05/21 10:52:36
 Triptohell.info
#1338 posted by onetruepurple [93.105.236.63] on 2014/05/21 11:20:55
Blocked by NOD32 :(
 Disable The Religious Filtering
#1339 posted by Spirit [92.196.113.28] on 2014/05/21 11:27:08
#1340 posted by Johnny Law [50.242.126.113] on 2014/05/21 19:40:33
Speaking of FTE things, what is the general story about the lack of public stable releases for FTEQW etc.? I ain't mad, just curious. I see there's development still churning away, but I typically avoid using dev builds of stuff unless there's a specific reason.
#1341 posted by Spike [86.169.38.140] on 2014/05/21 22:44:32
as the v1 release proved, stable builds are not really that much more stable than stuff that has since been fixed...
I'm not really a milestone kind of person, thus there's not really any point where a release is any more worthy than another (generally the 'best' time is just before I commit some huge awesome feature that's likely to break everything, which means that the release is effectively crippleware).
plus I'm too lazy to figure out how to edit the site. :s
 Beware Of The Leopard
#1342 posted by Preach [77.98.165.95] on 2014/05/21 22:52:56
Yeah, it seems a shame that this kind of stuff gets lost - I guess it's the downside to that continuous integration, nightly builds stuff - there's less inclination to tie things up into a release milestone. I'll make a blog post once I've messed around with it, which will at least give it a tad more coverage...
 New Version Of Win64-fteqccgui.exe
#1343 posted by Qmaster [50.40.188.204] on 2014/05/28 00:31:47
@Spike: Nice! New version has some nice bug fixes (like not being able to minimize a fullscreen window).
The new version though is giving me a bunch of similar wierd warnings though:
client.qc:761: warning F307: type mismatch: void() to void(entity attacker, float damage) entity.th_pain
It's this line in client.qc under
void () PutClientInServer = {
...
...
self.th_pain = player_pain;
...
...
}
Uh...what?
Since when did assigning a function to a .func need a type to match?
Anyways, compiles nicely. Also, I think it's a tad bit faster.
 Functions Not Matching Types
#1344 posted by Preach [77.98.165.95] on 2014/05/28 01:05:04
Functions not matching field types quickly leads to functions being called with the wrong number of paramters. Please see:
http://www.celephais.net/board/view_thread.php?id=1&start=23053&end=23102
...and...
http://www.celephais.net/board/view_thread.php?id=60398&start=185&end=200
...for the kind of fucking-awful-to-debug issues that this warning protects you from.
Now, in one direction you're probably quite safe: if you assign functions without parameters to fields which expect parameters then the engine is doing benign busy-work for no good reason. On the other hand, assigning functions with parameters to fields which aren't going to set them will send you to bug city in entirely unpredictable ways.
#1345 posted by Spike [86.169.38.140] on 2014/05/28 03:54:55
> Since when did assigning a function to a .func need a type to match?
Since people tried stuff like:
string(.void(),float,string) ohnoeswtf;
void() foo =
{
self.th_pain = ohnoeswtf;
};
you get the idea...
 Wow
#1346 posted by Qmaster [70.195.67.95] on 2014/05/29 04:59:45
I had no idea that could happen Preach. That makes so much sense now. I suppose the only reason the PARMs don't get 'scrubbed' was to be more optimized? Anyways I'll definitely check these warnings out now.
 Warnings For Th_Pain
#1347 posted by Qmaster [50.40.136.176] on 2014/06/03 03:57:03
The warning lies in the original code's usage of the th_pain function. Calls to a th_pain without sending any arguments (e.g. void () player_pain... ) are generating warnings all over the place in untouched progs.dat vs 1.06. Attempting to correct this by making all instances of a pain function include "(entity attacker, float damage)" as per defs.qc's definition would still generate some warnings, for instance in the case of func_door_secret assigning .use to the pain function for shootable secrets.
Perhaps a future update could suppress these particular instances. Just FYI, I don't know how yall are ignoring these warnings, they're kinda annoying. Anyways, I'll try to ignore them.
 Potential Fix
#1348 posted by Preach [77.98.165.95] on 2014/06/03 08:55:32
They are the more difficult ones to fix. I can see one way to do it, but I'm still deciding if this the best way to go about it. Keep the fd_secret_use function as it is, but create a new function as follows:
void(entity attacker, float damage) fd_secret_pain =
{
fd_secret_use();
}
This certainly fixes the warning, although it is using an extra stack frame to resolve a benign warning. In the secret door case you could get rid of the need for a pain function if you made the health of the door 1, so it dies to every attach. However, I've had the same problem on monsters which I can't afford to rewrite in that way.
#1349 posted by Spike [86.136.151.249] on 2014/06/04 08:49:53
Should be able to cast it.
self.th_pain = (void(entity,float))fd_secret_use;
Essentually an 'I know, now please shut up' option.
 I Suck At QC
#1350 posted by dwere [213.87.133.78] on 2014/06/12 20:56:22
What's the difference between checking other.takedamage and other.health in a projectile touch function?
When a monster dies, there's a short period when it's still solid. Hitting it while it's in such condition is pretty much like hitting a regular wall. It's very hard to notice in normal circumstances, but I have a weapon that shoots ricocheting nails, and on more than one occasion nails bounced from dying monsters right into my face.
Laser touch function in hipnotic QC uses other.health rather than other.takedamage to detect a damageable entity. I tried that and it helped. What I don't understand is why.
#1351 posted by Spike [86.182.103.17] on 2014/06/12 21:20:38
cthon has health (3 on hard, woo) but is not shootable.
monsters that have been killed will have a lingering <1 health value, despite no longer being shootable.
if you're paranoid about players doing exactly enough damage to drop a monster to 0 health exactly, then you might want to test for a longering th_die instead.
#1352 posted by dwere [213.87.133.78] on 2014/06/12 23:09:21
Thanks. I think I'll just add an additional check for a classname (Chthon shouldn't really bleed from a nail) and call it a day.
#1353 posted by Lunaran [70.124.85.229] on 2014/06/13 03:22:50
Monsters become DAMAGE_NO in Killed(), but each monster has 'self.solid = SOLID_NOT' somewhere a couple frames into each death anim.
You could check 'self.flags & FL_MONSTER' in your nail ricochet touch.
#1354 posted by dwere [213.87.138.11] on 2014/06/14 12:39:55
I went with FL_MONSTER check after takedamage check returns false. Thanks for replies!
 Short Post
#1355 posted by Preach [77.98.165.95] on 2014/06/18 09:44:50
I promised last week I'd put up an attempt to explain the way the origin key works for brush-based entities. Here's that post:
http://tomeofpreach.wordpress.com/2014/06/18/origin-of-the-entities/
Coming up next: using a nosave variable to (among other things) detect when the engine loads a saved game and run some custom QC.
 Longer Post
#1356 posted by Preach [77.98.165.95] on 2014/06/19 02:23:39
Here's the guide to using nosave to create a LoadGame function that runs only when the player loads a saved game.
http://tomeofpreach.wordpress.com/2014/06/19/save-game-detection/
Also bonus content on how you can create CheckExtension friendly code which allows for cross-engine save file compatibility (hint: it uses nosave again, that's the theme of the blog...)
#1357 posted by Spike [81.151.32.151] on 2014/06/19 06:17:58
the noload feature:
float _foo;
will be saved, but not loaded. works with any qcc. this quirk may be useful if you wish to write the extensions the saved game previously expected, for debugging, without causing any issues later.
 Aha
#1358 posted by Preach [77.98.165.95] on 2014/06/19 08:28:31
So it's like the counterpart to the "private fields" trick, which creates a field mappers can't set on your entities by naming the field with a leading underscore...
#1359 posted by Lunaran [24.247.68.254] on 2014/06/19 18:44:26
Quoth for instance uses it to sort out the screen tints for the custom powerups, restore stuffcmds the mapper has applied, and warn you if you load an incompatible save from an earlier version of the mod.
Really?
I've spent a long time thrashing around in qc trying to figure out how to do all of those things.
A big thank you, once again, for keeping the Quoth source closed, so that nobody can learn anything from it until revealed years later on Preach's blog.
#1360 posted by Lunaran [24.247.68.254] on 2014/06/19 19:54:44
Got it working, but I had to use "nosave float" and not "float nosave" like your post says. This is with the latest fteqcc downloaded from the super-secret triptohell moodles directory above.
 Yeah, Well
#1361 posted by Preach [77.98.165.95] on 2014/06/19 21:05:36
There aren't any trade secrets in Quoth, if there's any other features people want to understand just shout and I'll put it on the tutorial list. Thanks for the pointer on the keyword order, I'll fix that in the text.
 QC Blackbox
#1362 posted by sock [190.225.198.98] on 2014/06/19 22:29:38
There aren't any trade secrets in Quoth, if there's any other features people want to understand just shout
I think you are completely wrong! I have seen CZG, necro, Kinn and metlslime QC files and all of them were amazing sets of code which has made my understanding of QC better. I think you seriously under estimate the value of letting people see a working codebase. Cherry picking examples is all well and good but seeing the whole picture is damn right educational.
For example I would love to see the AI code for a bob from Quoth, I love how they move, shoot and even their crazy death is cool. Another gem I would love to see is the working code for the ladders in Quoth, not text descriptions but actually working QC files.
There are tons of things about Quoth QC that would be awesome to look at and I personally believe the greatest thing you could ever do for this community is let people see what QC tricks you have done.
 Hm
#1363 posted by ijed [200.73.66.2] on 2014/06/20 15:40:15
I should probably post the RMQ qc somewhere.
<Most hated project ever yadda yadda go fuck yourself>
Would any of the people the above didn't apply to be interested in seeing it?
There are some gems in there, like Supa's NPC code and the Shambler lightning attack visual improvement.
Exploding zombies and fast zombies were mine, and pretty cool if I do say so myself :>
I think next map (after I release the current one) will have the exploders in it.
#1364 posted by onetruepurple [93.105.236.245] on 2014/06/20 18:51:34
For all its faults, RMQ had some wonderful things in the qc.
 RJ's
#1365 posted by ijed [200.73.66.2] on 2014/06/20 18:58:45
Map were also incredibly epic...
 Maps
#1366 posted by ijed [200.73.66.2] on 2014/06/20 18:58:55
 ...rj's Maps...
#1367 posted by onetruepurple [93.105.236.245] on 2014/06/20 19:06:29
 Ugh
#1368 posted by Drew [174.91.195.251] on 2014/06/20 23:08:59
Wish those would get released standalone.
 Can Somebody Smart Do This Thing But For Scrags.
#1369 posted by onetruepurple [93.105.236.245] on 2014/06/21 02:30:52
#1370 posted by FifthElephant [82.24.73.240] on 2014/06/21 10:26:57
That looks flocking amazing!
 Using FTEQCC
#1371 posted by necros [99.227.110.3] on 2014/06/21 20:08:06
Why is:
void() frame = [ $f1, self.th_run ] {};
not allowed?
error: Type mismatch on redeclaration of self. void (), should be entity
 QC Opcodes
#1372 posted by Preach [77.98.165.95] on 2014/06/21 21:30:53
In short, because the newthink function has to be determined at compile time for the frame definitions to work.
In long: the [frame, newthink] notation in QC is usually described as a shorthand, but it's actually a bit more than that. When QC is compiled it gets turned into opcodes (like java). Most of the opcodes are pretty generic and normal, but for efficiency reasons that made sense in '96 there's a special opcode which does all the basic monster housekeeping:
* it sets the frame
* it sets the new think function
* it sets nextthink to time 0.1
The only way to create something with this opcode is to use the special [] notation, but once you do, you're locked into using the opcode, and it needs to hardcode the function. I suppose in theory a compiler could treat the [] differently - detect when a dynamic expression has been input and in that case skip the opcode optimisation in favour or writing the relevant QC manually. Might break the principle of least surprise though...
#1373 posted by Spike [81.151.32.151] on 2014/06/21 21:40:42
state functions need special handling if only because they're the one place where a variable can be used without prototyping it first.
this means that the qcc is expecting explicitly a function name and not a statement/formula, and is naturally complaining when the name it saw (self) was not in fact a function as required by the opcode.
the .th_run] part of the definition has not been tokenized yet.
#1374 posted by necros [99.227.110.3] on 2014/06/21 22:28:30
thanks, that makes sense. :)
 Aiming
#1375 posted by ijed [200.73.66.2] on 2014/06/24 15:03:11
I've got a large enemy that fires twin streams of projectiles from either hand, each being offset quite a bit from the centre to either side.
The point they aim at has a scattered origin, randomising within a small volume to make the fire pattern more interesting.
In a small test map the enemy works fine, but in my main map it occasionally looks like it's the point of origin and not the point of aim that's getting slightly randomised.
Does this sound like an engine precision issue?
#1376 posted by Spike [81.151.32.151] on 2014/06/24 17:22:01
depends how large your projectiles are.
with the vanilla network protocol, origins have 1/8th qu precision.
angles have 1/256th revolution precision
on a large object with offset origins (read: rotating bsp doors), the angular precision can result in significant jerks. this is generally not much of an issue with models though.
if you want to test if its an engine precision thing, try the following engine+cvar settings.
fte: compare sv_bigcoords 0(low/vanilla precision) to 1(16bit angles, 32bit float coords). restart the map for it to take effect.
dp: compare sv_protocol 'quake' (vanilla) to 'dpp7' (16bit angles, 32bit float coords), or whatever it was. not sure what you need to do to actually apply the new setting.
 They're Points
#1377 posted by ijed [200.28.237.193] on 2014/06/24 20:16:54
So that pretty much rules that out. I need to debug again.
Thanks for the answer.
#1378 posted by necros [99.227.110.3] on 2014/06/25 04:18:03
you're using makevectors and v_* to do the offsets?
#1379 posted by Spike [81.151.32.151] on 2014/06/25 09:03:54
yeah, makevectors(self.angles) is bad if self.angles_x will ever be anything but 0.
makevectors pitch angle is inverted relative to non-brush models (old id bug).
yes, its inverted relative to vectoangles too.
 No Makevectors...
#1380 posted by ijed [200.73.66.2] on 2014/06/25 14:40:14
I got it working eventually in a testmap like I say, without any weirdness. Just in my large BSP2 it seems like the org (point of origin) is behaving like the vec (point of aim).
org1 = self.origin + v_forward * 20 + v_right * 36 + '0 0 24'; //right hand
org2 = self.origin + v_forward * 20 + v_right * -36 + '0 0 24'; //left hand
vec1 = self.enemy.origin + RandomOffset(22) - org1;
vec2 = self.enemy.origin + RandomOffset(22) - org2;
The RandomOffset function just does this:
local vector offset;
offset_x = crandom() * offset_amt;
offset_y = crandom() * offset_amt;
offset_z = crandom() * offset_amt;
return offset;
Am I missing something obvious there or taking something for granted? My coding is built on trial and lots of error, meaning I kn ow nothing of good practices etc. I don't have makevectors anywhere in the qc file actually...
 Well There's Yer Problem
#1381 posted by Lunaran [70.124.85.229] on 2014/06/25 16:14:50
makevectors is where v_forward and v_right get populated. if you don't call it on self before doing all that, they'll be left over v_forward and v_right vectors from whatever thing last used them.
 Hah, So...
#1382 posted by ijed [200.73.66.2] on 2014/06/25 17:47:22
It was all in my head about it only happening in the larger map.
Will test it out tonight, thanks.
 So It Works
#1383 posted by ijed [186.79.224.94] on 2014/06/26 03:17:19
After all that pissing about it turns out I just forgot to reset the vectors.
But it works now!
Screaming plasma death coming to a mod near you 'soon'.
 Writing Some Tools...
#1384 posted by than [126.204.164.119] on 2014/06/26 15:38:11
I'm currently trying to make some simple tools for working with wads and paks that work via web browsers. I know this sounds pointless, but given that texmex, qped and pakexplorer are windows only, I thought it might be worthwhile so that people on any platform can fiddle with these formats.
Although both formats are trivial, I've noticed a few weird things with the contained images. I've been looking at the (old and eronious in a few spots) quake specs, and there seem to be three different types of image format used in Quake:
1. pixels
palette files, conchars in gfx.wad, colormap.lmp and maybe others
2. width, height, pixels
most, if not all lmps and status images in gfx.wad
3. name, width, height, pixels1, pixels2, pixels3, pixels4
all standard textures contained in most wads and bsp files
WAD file entries contain a type parameter that specify which format is used, but I've noticed that this isn't always correct. In gfx.wad, for example, the file conchars is listed as the same type as a regular wall texture (type 3), yet has no header and is exactly 128x128 bytes. The lmp files in pak0.pak also contain a couple of textures that have no header, whereas the others do, and a handful of them are strange sizes.
The mystery lmp files are 3352 bytes each. Since all images are meant to have width and height that are multiples of 8 the size doesn't work out, even accounting for an 8 byte width x height header. Just wondering what kind of files these are. The names are " gfx/dim_???.lmp" and "gfx/netmen?.lmp".
Should I just ignore the size and assume that aside from the special cases I mentioned above, that all UI textures and lmps are class 2 and all wall textures are class 3?
 That Sounds Awesome
#1385 posted by Lunaran [216.188.254.244] on 2014/06/27 02:31:13
but to answer your question, I don't know. probably!
#1386 posted by Spike [81.151.32.151] on 2014/06/27 04:27:32
tbh I'd just special-case it.
netmen* are image lumps. serial, modem, ipx, tcp, etc options.
dim_* are greyed out versions of those.
the *8 size applies _only_ to transparent lumps, and only to their width. the height can always be any value it wants.
for non-transparent lumps, the width can be anything, even 1... at least in the software renderer. I imagine the gl renderer mandates a multiple-of-4 width, but not height.
I should probaly mention at this point that hexen2 has some &3 widths in its gfx.wad.
the two lmp groups that you name are not transparent, and thus can be any size they want, ish.
palette, colormap, conchars. these have special handling in the engine. the engine doesn't care about types.
other images in gfx.wad should never be mip textures, as that would be pointless.
any other wad with any other name should contain mip textures. any time that that's broken you can expect issues all round.
what I'm trying to say is that there isn't really any reason that the data must be of a specific format, unless the thing trying to read it requires it to be.
.wad dates back to doom, it really is just a collection of file lumps rather than some clever format with well-defined file types.
 Spike
#1387 posted by than [126.204.164.119] on 2014/06/27 05:28:57
Thanks. I put a special case for conchars already, so I guess I'll do the same for lmp. Maybe there is some formula that would allow me to figure out the header type, but I'm not sure. I guess special case by name and size is probably safest :/
 Wad Lump Types
#1388 posted by LordHavoc [50.193.192.106] on 2014/06/27 05:29:51
Than: it sounds like you already identified the special files for the most part, but I will clarify:
gfx.wad conchars.lmp - 128x128 raw image, color 0 is transparent (unlike other pics)
gfx.wad colormap.lmp - 256x64 image of nearest-match colors for light level shading (0-63, with 32 as neutral, 63 as 2x brightness), followed by a 32bit integer (which sometimes stored as a single byte instead), which is 32 in id1 and typically 32 in all mods (there might be some with 0), this number is how many palette entries are fullbright (256-n is the start of the n fullbright colors in other words).
gfx.wad palette.lmp - 256x3 array of RGB colors, not copyrighted (John Carmack explicitly stated that id do not care if you copy the palette, or even embed it in code).
Miptex wads also contain palette.lmp, but all other files in them are .mip.
All other files are consistently formatted, the transparent color in .lmp (and .spr for what it's worth) is 255, no other format supports transparent pixels.
Size restrictions:
.lmp - no real restrictions, but glquake has errors if the width is not a multiple of 4 (software quake has no such restriction), and software quake corrupts memory if an image exceeds the screen boundaries, so even centered 320x200 image is the practical limit.
.mip - glquake has errors if the width is not a multiple of 4, software quake requires the width and height to be a multiple of 16 (due to surfacecache having a hard-wired function for applying lightmaps to a 2x2, 4x4, 8x8, or 16x16 grouping of pixels).
If you wanted to solve a problem that has probably been vexing people for some years now, why not make a converter for combining two .tga 32bit color images (one .tga for albedo/diffuse, and one _glow.tga) into one .mip file (or .pcx for loading into .mdl and .spr editors) where the glow colors are mapped to fullbright range (according to colormap.lmp's value for how many fullbrights exist) and the regular .tga's colors map only into non-fullbright colors, it's always been a pet peeve of mine with the tools at hand, but as I was kind of rendering the quake formats obsolete over the years I never bothered.
Note that there are some special files outside the .wad as well that may not be obvious:
gfx/qpop.lmp - this is a 16x16 image (I think in Quake palette?) that is the quake logo, the general going theory on this is that the quake logo is trademarked and thus it would give them a way to sue people for distributing quake mods designed to be used with shareware quake (which lacks this file, and thus refuses to run mods).
end1.bin - shareware quake dos text to show on exit
end2.bin - registered quake dos text to show on exit
 /me Weeps
#1389 posted by Spirit [92.196.109.23] on 2014/06/27 08:18:56
 I Have Two Stupid Questions
#1390 posted by dwere [213.87.130.108] on 2014/06/27 18:01:30
1. I want to pass an entity field to a function. What's more efficient: to pass one field (say, a string) or an entity pointer? Assuming that other fields won't be needed in said function.
2. There are various styles of naming the functions in id1 QC: DerpDerp(), derp_derp(), even Derp_Derp(). Is that because various programmers didn't care about naming conventions, or is that meaningful in some way?
 Answers
#1391 posted by Preach [77.98.165.95] on 2014/06/27 20:05:12
1. Pass the string, not the entity. All strings in QC are immutable and all you're doing is copying around the pointer, which is cheap. On the other hand if you send the entity, then you have to go through an extra two intructions each time you need to access the string, which is marginally more expensive.
2. There's no meaning, it's just that lots of id staff worked on the code and had different coding styles. There isn't even a good way to tidy the codebase back up into one convention: the fixed QC functions that the engine calls are all InitialCapital style like StartFrame and PutClientInServer, but unless you're going for a total conversion all the classnames are in lower_case_underscore format and you're stuck with those function name too!
So do whatever you're comfortable with in your own code, but I would recommend obeying the conventions on classnames - stick with lower_case_underscore for the names, starting with func_ for visible brush entities, trigger_ for invisible brush entities, and monster_, item_ OR info_ for point entities.
#1392 posted by Spike [86.173.175.99] on 2014/06/28 00:40:42
1. If you pass the value, you can't write to it. The caller will need an extra intruction to pass the value, which is the same as if you read it once inside the function anyway.
If you pass the entity, you can change it to some other string, but reading will cost 1 more instruction (1 to read, 2 to write).
2. For engine->qc calls, I generally expect camelback function names combined with at least one underscore! which helps when the majority of functions are all lowercase. less possible conflicts.
spawn functions should probably be lower case, just because. however, there's at least one that isn't. oh well.
#1393 posted by JneeraZ [174.97.226.218] on 2014/06/28 12:56:42
Is QC performance ever a real concern these days to where an extra instruction here or there makes the difference between smooth and choppy gameplay? I don't know, I'm seriously asking.
#1394 posted by dwere [213.87.134.2] on 2014/06/28 13:50:10
Thanks for the answers.
Willem, I doubt it. I just don't want to pick any bad habits if I can avoid it. Besides, I was curious.
#1395 posted by necros [99.227.110.3] on 2014/06/28 14:13:40
No. But very rarely yes.
A lot of code gets run once per frame or once every animation frame (typically 10 times a second). This kind of code can be messy without impacting performance on even a semi-modern machine.
The times where it can matter are when you are doing things in a loop during the same frame. For example, pathfinding, or searching for new enemy targets.
#1396 posted by JneeraZ [174.97.226.218] on 2014/06/28 15:55:41
dwere
Sure, I understand that. Tinkering with something like Quake is fun because you get to understand every nook and cranny after awhile. It's stable and unchanging and there's something comfortable about that.
#1397 posted by JneeraZ [174.97.226.218] on 2014/06/28 15:56:45
And something a little disheartening as a programmer. As you're figuring out more and more about how things work and what does what, you realize that Carmack came up with and wrote most of this from scratch 18+ years ago. Damn him...
#1398 posted by necros [99.227.110.3] on 2014/06/28 20:26:45
self.function = (void(float))funcWithFloatArg;
results in:
type mismatch for = (pointer and __variant)
What version of FTEQCC do I need to make that work?
 A New Version
#1399 posted by Preach [77.98.165.95] on 2014/06/28 21:15:26
http://triptohell.info/moodles/fteqcc/ does all of that, as well as adding a bunch of warning for NOT doing it.
#1400 posted by necros [99.227.110.3] on 2014/06/28 21:38:27
Thanks! Shame that's buried on some hidden server. :(
 FTEQCC Documentation
#1401 posted by necros [99.227.110.3] on 2014/06/29 00:01:54
Is there any documentation for this?
All I could find was this: http://www.fteqw.com/wiki/index.php?title=FTEQCC_FAQ
For example, is it possible to have an array that is an entity member?
 Guess I Could Just Try It...
#1402 posted by necros [99.227.110.3] on 2014/06/29 00:03:53
seems to compile without errors.
#1403 posted by Spike [86.163.87.128] on 2014/06/29 00:58:23
if it doesn't crash, then its a feature!
 Lordhavoc
#1404 posted by than [126.204.168.155] on 2014/06/29 03:11:39
Thanks for all that info! Very useful to know.
I wonder how the guys behind the Quake specs figured it all out before the QuakeC source etc. was officially released by id. Must have taken a lot of trial and error.
 Spirit
#1405 posted by than [126.204.168.155] on 2014/06/29 03:12:48
Spirit: Yeah, I was looking at the Quake Wiki the other day and thinking it looks a bit sad and needs some love. Perhaps we should get as much info from the Quake Specs about file formats as possible on the wiki, and finish off the level and monsters guide.
Part of the problem I had before is that there's just too much information per thing and it's annoying to have to basically write an entire article just about a level in a game that was released in 1996, even if that game happens to be one's favourite game. It might be worth looking at how the pages are formatted and thinking how to divide it up within the article so that more of the information is optional.
 Crosshair 0
#1406 posted by Lunaran [216.188.254.244] on 2014/07/04 00:30:14
Okay.
I want to hide the crosshair during centerprints and other special events. This is easy.
I also want to remember the user's crosshair preference, because the only way to hide the crosshair is set the cvar to 0 .
It was easy when I was just assuming that the user's preference was "use the crosshair, always" because what kind of lunatic wouldn't? I forget who or where, but someone recently posted somewhere on func that they hate playing Quake with the crosshair on because it makes their aim worse or something. Fine, whatever, I'll try and support it.
If I save the value in a float in the progs somewhere, the crosshair doesn't come back if I restart the level or load a new map while it's hidden. If I save it in a safe cvar (like 'temp1' or setting a high bit in the value of 'registered'), the crosshair doesn't come back if I quit the game while it's hidden and restart later, because those cvars get reset.
Is there any other cvar I can use? Are the 'saved1-4' cvars safe to faff with?
#1407 posted by necros [99.227.110.3] on 2014/07/04 01:02:25
you should consider using a nosave var which will cause the progs to re-evaluate the state of the crosshair visibility after a map load.
#1408 posted by Scampie [72.12.65.92] on 2014/07/04 01:06:25
this isn't an answer, nor likely helpful.
...but is it worth going to all the trouble to fix that bug (crosshair setting doesn't return if user quits during a centerprint)? I understand the desire to fix it, but on the other hand... you're making a mod not a AAA title that needs to get certified. It doesn't seem like it would be that common an issue, nor one that most users couldn't fix themselves by turning the crosshair back on if it was off when they loaded a save.
 Pfffft
#1409 posted by FifthElephant [82.24.73.240] on 2014/07/04 01:12:11
I didn't need a crosshair when quake came out and I certainly don't need one after 17 years of playing the game.
The hitboxes for the enemies are bloody huge, it's not needed!
 Yep
#1410 posted by mfx [78.55.109.53] on 2014/07/04 01:13:56
no crosshair. No one plays with that;)
#1411 posted by JneeraZ [174.97.226.218] on 2014/07/04 01:13:59
I don't use a crosshair. Shots go into the middle of the screen. It's not THAT hard to predict. :P
#1412 posted by Lunaran [216.188.254.244] on 2014/07/04 01:33:41
you should consider using a nosave var
that's not going to help. when I hide the crosshair, "crosshair 0" gets written to the config. no amount of qc-only shenanigans will restore it because quake itself has forgotten what it was.
but is it worth going to all the trouble to fix that bug
it annoys the hell out of me, so yes :)
everyone else and your no crosshairs
you fucking people
Apparently the cvars saved1-saved4 were added in SoA and never used, for anything, by anyone. I'm going to go with using one as a backup crosshair cvar, because it's persistent across game starts. The only problem with this is that if someone is a crosshair user and decides halfway through lunsp2 to join you fucking people the crosshair will keep coming back unless he sets 'saved1' to 0 also. I can live with this.
#1413 posted by necros [99.227.110.3] on 2014/07/04 01:45:51
nosave float isCrosshairCheckDone;
float crosshairVal = -1;
float isMessageDisplayed
displayMessage()
{
crosshairVal = getCvar(crosshair) //or whatever the method is
isMessageDisplayed = true;
isCrosshairCheckDone = false;
}
messageDone()
{
isMessageDisplayed = false;
isCrosshairCheckDone = false;
}
and then in player prethink or something:
if (!isCrosshairCheckDone)
{
if (!isMessageDisplayed && crosshairVal != -1)
setCvar(crosshair, crosshairVal); //or whatever way it works
else
setCvar(crosshair, 0);
isCrosshairCheckDone = true;
}
probably buggy but you get the general idea.
#1414 posted by necros [99.227.110.3] on 2014/07/04 01:47:06
yup bug:
if (!isCrosshairCheckDone)
{
if (!isMessageDisplayed && crosshairVal != -1)
setCvar(crosshair, crosshairVal); //or whatever way it works
else if (isMessageDisplayed)
setCvar(crosshair, 0);
isCrosshairCheckDone = true;
}
#1415 posted by metlslime [159.153.4.50] on 2014/07/04 01:58:07
did you try just adding some blank lines to the centerprint so that it gets shifted upwards?
 Also:
#1416 posted by metlslime [159.153.4.50] on 2014/07/04 02:04:02
this problem of centerprints and crosshairs has never occurred to me before recently, since I always play without a crosshair. (I can only do this in classic FPS games with centered gun models, though.)
#1417 posted by necros [99.227.110.3] on 2014/07/04 02:27:21
only thing with adding newlines on centerprints is that there is somewhat inconsistent behaviour across engines. darkplaces, for example, places centerprints higher up the screen, so adding the newlines in that case puts them even higher.
it's not so bad it breaks, but it needs to be tested.
#1418 posted by Lunaran [99.112.162.57] on 2014/07/04 03:53:29
crosshairVal = getCvar(crosshair)
If the crosshair was hidden the last time I quickloaded/died/quit, that cvar was set to 0 at the time and got saved that way. getCvar returns 0 because it no longer represents my actual crosshair preference.
#1419 posted by necros [99.227.110.3] on 2014/07/04 04:15:16
ok, then just do some clean up and reset the var to -1 and then check in the display method.
#1420 posted by Lunaran [99.112.162.57] on 2014/07/04 04:36:08
 @Lunaran
#1421 posted by Baker [69.47.162.203] on 2014/07/04 05:35:05
You seem pretty non-thrilled about the crosshair thing.
And it looks like you making and wasting time worrying about this.
I'll produce a FitzQuake 0.85 and a Mark V with an option "gl_crosshair_hide_on_centerprint" (or whatever) that will always hide the crosshair with centerprint on the screen and a simple tutorial to implement.
Far better for you to be making a map than messing with awkward QuakeC solutions.
It would suck to see a quality single player release poisoned with awkward QuakeC and screwing with your cvars.
 Baker
#1422 posted by FifthElephant [82.24.73.240] on 2014/07/04 09:32:00
Can you at least fix non power of two rendering?
 CSQC.
#1423 posted by onetruepurple [93.105.236.126] on 2014/07/04 10:24:35
Better solution than an engine hack.
 CSQC...
#1424 posted by Spike [86.163.87.128] on 2014/07/04 12:34:24
But csqc is much more involved, small tweaks are a gateway drug!
the crosshair/centerprint thing is a general engine issue, so should probably be implemented anyway.
Besides, I doubt baker has the time to add csqc support to two engines...
@baker, markv with bsp2? I'm just curious mostly.
 Hmm
#1425 posted by onetruepurple [93.105.236.126] on 2014/07/04 12:35:20
I do have a "fitzquake_mark_v_bsp2.exe" in my Quake folder...
 Ah
#1426 posted by onetruepurple [93.105.236.126] on 2014/07/04 12:38:58
I see where it came from, now.
#1427 posted by Spike [86.163.87.128] on 2014/07/04 12:40:41
Yeah, me. Hence why my curiosity. :P
 Ahh!
#1428 posted by mfx [85.180.244.35] on 2014/07/04 13:30:43
 @Can You At Least Fix Non Power Of Two Rendering?
#1429 posted by Baker [69.47.162.203] on 2014/07/04 16:06:42
Uh? What is an example? Do you mean textures that don't comply to the Quake standards listed in http://www.celephais.net/stuff/texturefaq.htm ? Or are you talking external textures or what?
Or do you mean something else?
[I have been thinking about a revision of Mark V to tidy up some of the things pointed out in the thread.]
#1430 posted by Johnny Law [64.134.132.150] on 2014/07/04 16:11:04
Quick comment on this:
> Apparently the cvars saved1-saved4 were added in SoA and never used, for anything, by anyone.
FYI frikbots use saved1.
#1431 posted by FifthElephant [213.205.236.30] on 2014/07/04 16:13:44
I can't give an example now because im in work. But some textures go blurry if they are a weird size. Best exanple I know right now is the large metal panel texturre on ziggurat vertigo
 @Spike
#1432 posted by Baker [69.47.162.203] on 2014/07/04 16:16:55
@baker, markv with bsp2?
Not sure if I understand the question. But yeah if I do any kind of clean-up release of Mark V I will incorporate the bsp2 code you donated to the project.
[I'm kinda of preoccupied with trying to port Mark V to Android combing using FTEDroid and Q14A for ideas/pointers. Looking at FTEDroid source has been immensely helpful and is a bit shocking the extent of your implementation.]
 NPOT
#1433 posted by Spike [86.163.87.128] on 2014/07/04 18:13:32
just use https://www.opengl.org/registry/specs/ARB/texture_non_power_of_two.txt
or in other words, if that's supported, ignore the fact that its an npot texture and upload it regardless.
This avoids various columns/rows getting ignored/duped to resize it. Resizing is evil, mmkay?
iirc, vanilla glquake's code was fine with the npot check disabled - so long as the drivers support it.
 @baker
#1434 posted by FifthElephant [82.24.73.240] on 2014/07/04 23:44:26
#1435 posted by Lunaran [99.112.162.57] on 2014/07/05 01:37:21
FYI frikbots use saved1.
Good to know, although I don't know why/how someone would play a custom q1sp with frikbots.
And it looks like you making and wasting time worrying about this.
I'll produce a FitzQuake 0.85 and a Mark V with an option "gl_crosshair_hide_on_centerprint" (or whatever) that will always hide the crosshair with centerprint on the screen and a simple tutorial to implement.
That's very nice, but probably not necessary, and also not a help to people who prefer other engines. It probably looks like I'm spending far more time on this than I really am. And, if you're getting back to FQmk5 development, fix the bugs in the FQmk5 thread first :D
#1436 posted by JneeraZ [174.97.226.218] on 2014/07/05 12:36:35
Has anyone recently performed the super awesome service of compiling a set of "starting" QC files to begin building on top of?
Also, a link to a proper compiler for modern Quake?
The reason I ask is that I found some "clean 106 QC" code and I'm using FrikQCC to compile it but even a clean, base compile gives me some weird crap trying to run the mod like, "can't find level maps/info_player_start.bsp" which basically sounds like something is out of alignment.
Is there a place to go to get a good working base of QC and a proper compiler these days?
#1437 posted by JneeraZ [174.97.226.218] on 2014/07/05 12:37:53
I should mention that deleting the progs.dat file in the mod folder makes everything happy so it's definitely the QC.
#1438 posted by JneeraZ [174.97.226.218] on 2014/07/05 12:52:01
#1439 posted by JneeraZ [174.97.226.218] on 2014/07/05 12:52:39
Although the link to the FrikQCC compiler is dead (inside3d).
 Try
#1440 posted by ijed [190.22.56.52] on 2014/07/05 15:50:32
FTEQCC http://www.fteqw.com/
Been using it for years, very reliable.
 FTEQCC
#1441 posted by Preach [77.98.165.95] on 2014/07/05 22:25:38
There's a more recent version of FTEQCC at http://triptohell.info/moodles/fteqcc/ which has come up twice in the past month. It fixes at least one compilation bug I've encountered, so it's worth having for stability.
 FTE And Arrays
#1442 posted by necros [99.227.110.3] on 2014/07/06 03:18:51
void debugArrayPrint(float f)
{
bprint(ftos(f));
bprint("\n");
}
with this code:
bprint("debug test:\n");
float i = 0;
float array[5];
array[0] = -1;
array[1] = -2;
array[2] = -3;
array[3] = -4;
array[4] = -5;
float a[1];
a[0] = 1;
float b[2];
b[0] = 2;
b[1] = 3;
array = a;
for (i = 0; i < 1; i++)
debugArrayPrint(array[i]);
array = b;
for (i = 0; i < 2; i++)
debugArrayPrint(array[i]);
gives this output:
debug test:
1
2
-2
I would have expected:
debug test:
1
2
3
It seems like arrays are not handled the way they are in C and only copy the first element. Is it at all possible to pass them like pointers so that functions can freely take array pointers as arguments and return array pointers?
Like for example, if I wanted to create a vector system where we always push elements via a method (let's called it push_back), which would automatically copy the array to a larger one when space ran out.
#1443 posted by Spike [86.163.87.128] on 2014/07/07 13:20:32
Arrays are not pointers. Pointers don't exist in QC.
Remember that each and every access is expanded into a function call with a binary search inside in order to read/write the correct global for that index.
Or in other words, no pointers.
array = a; does indeed read+store the first element. it should return a pointer, and refuse to assign to a pointer. but it doesn't. this is a known bug, but as its (normally) an error anyway, it hasn't been a high priority to get it to throw a hissy fit instead. :P
Trying to compile such a statement is also an error in C (lhs is a const pointer, and thus assigning to it is a syntax error).
If you really want to copy one array to another, embedding it within a struct and copying the struct should work (in recentish triptohell builds anyway). The catch is that you can't copy specific blocks.
If you're using opcode extensions (and fteqw), you can just memcpy data from one array to another, but if you're not then you'll need to write some sort of loop to do it instead (use preprocessor?).
 MDL Question
#1444 posted by than [153.173.30.173] on 2014/07/07 14:32:53
I'm currently plodding along with my little Quake Web Tools thing, which is currently intended basically to allow you to view Quake file types by just dragging and dropping them onto a web page. Right now I am slowly working towards an MDL viewer, and have encountered an oddity - frame groups.
So, it appears that no models are actually using frame groups for anything, and that frames [i]could[/i] be grouped after extraction by simply processing them by name, since the frames are sorted by animation by name (e.g. walk1 - walk14 for the knight's walk cycle). I also seem to remember animations being defined explicitly in the Quake C somewhere.
So are frame groups used at all? What for? I need a model that has them that I can test with.
 ARGH!
#1445 posted by than [153.173.30.173] on 2014/07/07 14:52:31
ok, so I just discovered that the torch model 'flame.mdl' uses frame groups and my code works.
 Btw, Current Progress Here:
#1446 posted by than [153.173.30.173] on 2014/07/07 15:37:37
Currently there isn't much to show, but here it is for anyone interested:
http://pecope.co/experiments/quake_web_tools/QuakeWebTools.html
You can drag various Quake file types onto the drop zone at the top and get some kind of file preview, although currently the previews are very limited.
PAK: full file list and allows you to extract the files by clicking on the filename.
WAD: displays all textures in the wad
LMP: displays the image
BSP: displays the texture lump only. Basically the same as wad
MDL: displays skins only
PAL: displays the palette (treats it as a special case LMP)
SPR: does nothing currently, though there is some stub code, so you don't get an error.
My current plan is to make all of the main file types properly preview-able in a modern web browser on any platform said browser runs. This means that it should work fine in Chrome on MacOSX, Windows and Linux. Firefox worked last time I checked, and Opera should too. No idea about Safari and IE, but supporting different browsers is not a priority as long as it works on the good ones: Firefox and Chrome.
Once previewing files works properly (and perhaps before BSP preview works... I dunno) I'd like to start making a sort of browser based TexMex, although this is something that would likely be a lot of work - even if it only supports Quake 1 format WAD. Eventually editing other formats would be nice, but it's so much work to do things like an editor, and who knows, maybe someone will port TrenchBroom to asm.js :)
http://en.wikipedia.org/wiki/Asm.js
I wonder how WebQuake was made...
#1447 posted by JneeraZ [174.97.226.218] on 2014/07/07 15:54:13
The MDL format is SO much fun ... that's probably the most bizarre code I've ever written in relation to Quake. At every turn, there's something weird happening. And that's just reading. I never got around to writing it.
There were moments that felt like staring into the abyss...
 Than:
#1448 posted by necros [99.227.110.3] on 2014/07/08 01:24:20
 Willem:
#1449 posted by necros [99.227.110.3] on 2014/07/08 01:29:49
 Spike:
#1450 posted by necros [99.227.110.3] on 2014/07/08 01:37:46
Thanks for clearing that up. I knew that the arrays were a sort of hack but wasn't sure what the limitations were with them. Still, better than nothing!
Trying to compile such a statement is also an error in C (lhs is a const pointer, and thus assigning to it is a syntax error).
Yeah, the example had the array size declared because fteqcc wouldn't accept entity[]! That should have clued me in!
#1451 posted by JneeraZ [174.97.226.218] on 2014/07/08 01:48:41
necros
I don't doubt that it's possible, I just said I never got around to attempting to write it. :)
I had grand plans at one point to expand ToeTag into an entire Quake editing suite ... it was going to be amazing. And then one day I looked up from the keyboard and saw the mountain of code still ahead of me that needed writing and something broke inside of me.
Still ... it was going to be great.
 Yeah,
#1452 posted by necros [99.227.110.3] on 2014/07/08 02:22:04
i know what you mean.
I still want to make a model editor that'll let you do modern uv mapping like you can do in 3ds max or maya but both the crap code i wrote so far and the huge amount still left to be written puts me off, just not enough time. :(
 MDL
#1453 posted by than [153.173.30.173] on 2014/07/08 04:38:40
Well, I'm not planning on doing any MDL writing for the moment, although I might look into making a tool to update the skin lumps, since that's easy. Aside from the UV format being horrible, the vertices are packed into chars, so making a tool that allows you to alter a model with minimal loss of precision seems like it wouldn't be much fun.
As I mentioned, the only thing I'm thinking about seriously for now is a viewer and WAD file editor. Oh, and probably something that allows you to create and edit PAK files, since my current code merely allows you to extract the files from inside. At least PAK is a sane format... thank god JC never implemented compression :)
A MAP editor would be fucking awesome, but that's by far the most complicated thing, so I doubt I'll ever get that far. A port of Trenchbroom using asm.js might be feasible though, but it would require also porting wxWidgets, which I could barely even get to compile normally, let alone with asm.js.
Btw, for anyone who thinks web apps are shit (yeah, most of them are I guess), the tech does seem to have gotten a LOT better in the last couple of years thanks to HTML5 and an explosion of libraries to iron over browser incompatibilities and lack of support for various standard features. There's an entire modelling package here: http://clara.io/ Compared to that I guess a basic Quake editor would be quite easy.
 Necros
#1454 posted by than [153.173.30.173] on 2014/07/08 04:41:22
I'll look into it. Currently there is basically no error checking, and only bsp 29 is supported, so there are bound to be lots of places where shit goes wrong :)
 Necros
#1455 posted by than [39.2.242.10] on 2014/07/08 08:22:20
I examined the texture info lump that I had extracted and found that entry at index 176 was garbage. No idea what caused this; The textures before and after are all fine, so it doesn't seem to be some kind of problem with my reader, but I'll have another look. I can probably get past the error if I just ignore entries with an empty name, so I'll try that for now.
Can texmex open the file? How many textures does it contain? I get 263.
My tools don't care about limits, so maybe there is a problem with this going over the 256 texture standard limit causing an error I haven't handled? Then again, the textures are simply read from the offsets defined in the file, and 176 seems to be the only one that has read as garbage.
Any help you can offer on this would be appreciated.
 FYI
#1456 posted by than [39.2.242.10] on 2014/07/08 08:38:26
I fixed the bug by ignoring entries with no name. This is the data I extracted from the file regarding the garbage entry:
compression: 0
dsize: 21656952111104
name: ""
offset: 5770699
size: 21656952111104
type: 68
Clearly the size and filename are wrong. The offset seems OK, and the type and compression are both the same as the other entries in the file, so it looks like it's just a corrupted entry.
 To Keep This Monologue Going
#1457 posted by than [39.2.242.10] on 2014/07/08 08:40:03
If anyone has any experience loading models in three.js, please let me know. I am having a lot of trouble formatting MDL data in the format required by three.js because the documentation is very poor. Thank god for Chrome's awesome debugger.
#1458 posted by Spirit [92.196.103.55] on 2014/07/08 09:09:45
 God Damn
#1459 posted by than [39.2.242.10] on 2014/07/08 10:32:43
I didn't even bother to search because I just assumed nobody would have bothered. Anyway, that should make things easier :)
 Oh...
#1460 posted by than [39.2.242.10] on 2014/07/08 10:33:54
they are c programs. Kinda defeats the point :/
Source might have some insights though. Thanks!
 Wow
#1461 posted by than [39.2.242.10] on 2014/07/08 10:38:41
Seems he already did all of it. It's also pretty fast. Weird thing is that it only lets me play the sounds even though the messages in the log show that it's also parsing the other files.
Now I feel I've just totally been wasting my time and that I should kill myself.
 Btw...
#1462 posted by than [39.2.242.10] on 2014/07/08 10:42:00
Do you know if there is a version online somewhere that can preview the other types (I can only get it to preview sounds if I run it locally - even with a webserver behind it)
 Ah...
#1463 posted by than [39.2.242.10] on 2014/07/08 10:47:23
I looked at the code and he's just parsing the BSPS but not showing them in a viewer. Also, it's from two years ago, so I guess he got bored. Still pretty neat though, and I can steal his wav preview code for my own nefarious ends >:D
Thanks for the links, and sorry to spam the thread with another thanalogue.
 Thanalogue Pt.6
#1464 posted by than [39.2.242.10] on 2014/07/08 14:59:49
Well, after basically an entire day spent trying to get MDLs to render using three.js, I have finally got... non-textured pink and white MDL reviews. The texture is previewed below the window.
I will get this working one day, but probably not today. I'm so fucking pissed off with three.js's BufferGeometry class and lack of good documentation that I am going to give it a break for a day or two and perhaps work on .spr instead.
I also fixed that bug that Necros found.
http://pecope.co/experiments/quake_web_tools/QuakeWebTools.html
 Than:
#1465 posted by necros [99.227.110.3] on 2014/07/09 01:09:35
i see 261 textures in texmex O_O
 Ah...
#1466 posted by than [153.173.30.173] on 2014/07/09 05:41:49
I just checked and I get 261 too. With the broken texture it's 262, so I guess texmex ignores it also. Not sure why it's there or how it got there.
 MDLs
#1467 posted by than [126.204.164.171] on 2014/07/09 22:31:23
now working properly after I rewrote all the code to create three.js compatible data:
http://pecope.co/experiments/quake_web_tools/QuakeWebTools.html
Maybe I'll do spr then bsp viewing next. Need to start adding more controls for the viewers too.
#1468 posted by Lunaran [216.188.254.244] on 2014/07/10 22:26:41
the MDL viewer:
- needs view controls, yes
- should play anims at 10fps, they're all too fast now
- should allow me to select anims based on frame name and play them individually, or skip to an individual frame
- could easily support skin selection too
- would replace moldy old QME23 as my model previewer if you did this
 Lunaran
#1469 posted by than [126.204.192.91] on 2014/07/11 14:15:44
Thanks for the tips. I plan to do all of those things, but haven't yet, since I was just concentrating on making things work. Definitely want to do all that though, along with the option to display with or without vertex blending (with only at the moment, but trivial to disable) and it might be nice to display some kind of reference model for scale (a 128x128x128 3d box or something...)
I might also add skin lump editing, since that should be easy enough to do, but it will be something for later.
Will also be nice to allow you to preview models and other files that are inside pak files.
#1470 posted by Lunaran [99.112.162.57] on 2014/07/13 05:46:08
In WaterMove()
if (! (self.flags & FL_WATERJUMP) )
self.velocity = self.velocity - 0.8*wl*frametime*self.velocity;
self.velocity is reduced by an amount that is scaled by frametime, when self.velocity itself is not a framerate-relative variable. I also notice that the player doesn't actually move any slower in liquids. Is this a typo or another weird QCism?
#1471 posted by necros [99.227.110.3] on 2014/07/13 05:52:14
doing frametime * self.velocity gives you the amount of movement for that frame.
#1472 posted by Lunaran [99.112.162.57] on 2014/07/13 06:03:53
Yes, I understand that. The player isn't being moved there. The player isn't moved in qc at all, except when teleported, only his velocity - in units per second - is manipulated. The physics moves him.
#1473 posted by necros [99.227.110.3] on 2014/07/13 06:05:29
I must have misunderstood what you meant then. Why do you say that velocity is not framerate relative?
#1474 posted by necros [99.227.110.3] on 2014/07/13 06:06:41
Oh, ok, I see. Yes, so velocity itself is not framerate dependant; it's constant. But because we want to reduce speed by a constant amount, we have to multiply by the (varying) frametime to get the constant amount to reduce per frame.
#1475 posted by Lunaran [99.112.162.57] on 2014/07/13 06:11:53
... because it's in units per second.
Your framerate can vary as much as it wants and your velocity in units per second just is what it is. The amount the engine moves you per frame is different, but that's not the progs's business.
Okay, look.
if (! (self.flags & FL_WATERJUMP) )
self.velocity = self.velocity - 0.8*wl*frametime*self.velocity;
wl is waterlevel, which if you're in over your head is 3. Let's say self.velocity is '100 0 0'. Let's also say the framerate is 60, so frametime = 0.01666.
0.8 * 3 * 0.01666 * '100 0 0' works out to '4 0 0', so the player's velocity when underwater is reduced to '96 0 0'. What's the point?
#1476 posted by Lunaran [99.112.162.57] on 2014/07/13 06:12:50
Shit I see, this is applying additional friction?
#1477 posted by Lunaran [99.112.162.57] on 2014/07/13 06:15:51
Well, I commented it out and the player still slows to a halt when swimming underwater, so the engine clearly applies underwater drag anyway. So I'm still not clear on the purpose of those two lines.
#1478 posted by necros [99.227.110.3] on 2014/07/13 06:44:45
interesting, you're quite right:
void SV_WaterMove (void)
{
int i;
vec3_t wishvel;
float speed, newspeed, wishspeed, addspeed, accelspeed;
//
// user intentions
//
AngleVectors (sv_player->v.v_angle, forward, right, up);
for (i=0 ; i<3 ; i++)
wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
wishvel[2] -= 60; // drift towards bottom
else
wishvel[2] += cmd.upmove;
wishspeed = Length(wishvel);
if (wishspeed > sv_maxspeed.value)
{
VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
wishspeed = sv_maxspeed.value;
}
wishspeed *= 0.7;
//
// water friction
//
speed = Length (velocity);
if (speed)
{
newspeed = speed - host_frametime * speed * sv_friction.value;
if (newspeed < 0)
newspeed = 0;
VectorScale (velocity, newspeed/speed, velocity);
}
else
newspeed = 0;
//
// water acceleration
//
if (!wishspeed)
return;
addspeed = wishspeed - newspeed;
if (addspeed <= 0)
return;
VectorNormalize (wishvel);
accelspeed = sv_accelerate.value * wishspeed * host_frametime;
if (accelspeed > addspeed)
accelspeed = addspeed;
for (i=0 ; i<3 ; i++)
velocity[i] += accelspeed * wishvel[i];
}
seems to apply normal ground friction while in the water, and then the qc is apply extra friction.
you can see this in action by setting sv_friction to 0. you'll slide forever on ground, but in the water, you will still slow down.
very bizzare.
#1479 posted by necros [99.227.110.3] on 2014/07/13 06:47:17
i suppose... at some point they wanted the player to move slower than normal friction reduction..?
maybe it was easier to do it in QC than to modify the engine.
is there QC from the older version of the progs? maybe this was added in a later version?
#1480 posted by Lunaran [99.112.162.57] on 2014/07/13 07:34:27
It's like that in the 1.06 progs.
Also, this doesn't actually apply friction either, since player velocity is overridden by the exe based on the player's controls. It acts as a max speed cap, one that caps speed at 96%.
I'm leaning towards cruft/typo.
 Higher Friction
#1481 posted by Preach [77.98.165.95] on 2014/07/13 10:49:26
This still does the work of creating extra friction and should be left in. It doesn't have much effect when the player is actively swimming in a direction, as the new input tends to overcome the subtracted velocity every frame. It is important for when the player's velocity is not coming from input, like coming to a halt after the player stops swimming. Another example is where the player enters the water with a higher velocity than they can achieve by normal movement - like if they're falling from height into the water. Remove that code and the player will plunge deeper after falls into water, and there's a bigger chance they'll take fall damage from the bottom despite the water.
#1482 posted by Spike [86.178.8.118] on 2014/07/13 15:21:47
96% might not be big, but remember that its 96% every single frame.
it builds up.
quakeworld killed most velocity changes in the qc thankfully. the only one left is from damage. This was basically required for reliable prediction.
 Darkplaces Black And White
#1483 posted by Qmaster [50.40.182.176] on 2014/07/19 18:57:01
Is there a way to modify the color saturation in the DarkPlaces engine? I was curious about making an infrared vision effect by making the colors black and white, enabling fullbright, and setting fog to black with a short falloff, and maybe also toying with hdr settings to simulate eyes hurting from bright lights. Anyways are there hsv settings I'm missing?
 QC
#1484 posted by digs [94.41.99.29] on 2014/07/21 05:49:57
Where I can download sources v1.06 (*.qc) with fixed problems?
 Digs
#1485 posted by madfox [84.26.177.181] on 2014/07/21 08:22:29
Maybe try this one?
Or the wike tools
originals from 3D
 MadFox
#1486 posted by digs [94.41.99.29] on 2014/07/21 08:50:27
Thanks, but:
1. Looks like it's not single player sources
2&3. versions without fixed bugs
 Yes
#1487 posted by madfox [84.26.177.181] on 2014/07/22 00:31:50
After downloading I also was surprised to find a mod progs.
I searched my whole archive as I was sure I downloaded it.
Can't find it though.
Seven made a new progs but it only works in DarkPlaces.
I wonder if the errors that appear in FTEQcc can be overcome by new coding, on behalve of the double count rotfish.
 @digs
#1488 posted by Baker [69.47.162.203] on 2014/07/22 00:56:17
This one is probably the best with all the SP fixes:
https://gitorious.org/quakec-v1-01-clean
It took changes from "clean source" and "qip bug fixes" and combined it into one.
(Ignore the fact it says "1.01" -- that was the GPL base, you don't want to know more ...)
 @Baker
#1489 posted by digs [95.105.65.200] on 2014/07/22 04:22:51
Thanks!
After compile a have same 7 warnings. Example
doors.qc:626: warning F307: type mismatch: void() to void(entity attacker, float damage) entity.th_pain
doors:626: self.th_pain = SUB_Null;
function th_pain require 2 params, SUB_Null without params. Is it will work correctly?
#1490 posted by Qmaster [50.40.182.176] on 2014/07/22 06:30:10
#1491 posted by Qmaster [50.40.182.176] on 2014/07/22 06:31:56
should work fine, see the 3 or 4 posts in the forum link above.
#1492 posted by digs [92.50.131.158] on 2014/07/22 07:26:42
@QMaster thanks
 Got A Tricky One
#1493 posted by ijed [190.22.91.72] on 2014/07/23 15:28:30
So, I'm spawning monsters after the start of a level. Not just hiding them and then turning them on later, but actually creating new monster entities.
This involves a lot of tricky with spawn functions and precaches, but it works fine (props to gb/Preach).
What doesn't work is incrementing the monster count properly.
I'm using a custom writebyte to do this:
total_monsters = total_monsters + 1;
WriteByte (MSG_BROADCAST,SVC_UPDATESTAT);
WriteByte (MSG_BROADCAST,STAT_TOTALMONSTERS);
WriteLong (MSG_BROADCAST,total_monsters);
Which also works fine, but only the first time a monster is spawned. After that it increments the counter by 2 instead of 1. It doesn't keep on incrementing, no matter how many more I spawn, it just sticks at +2 per spawn.
I'm trying various solutions, but it almost seems like there is some engine side value which is being affected invisibly.
I've traced back all the occurances of total_monsters = total_monsters + 1; I can find and no luck. I've also shifted where/how its incremented a few times and turned off various parts of the process to try and localise the issue, but no luck so far.
Yes, I have an exclusion in walkmonster_start so that doesn't also add to the count...
Any ideas? I'm tempted to make it so that spawned creatures just don't add to the count, meaning the player can get >100% kills, but that's a sloppy fix.
 I Fixed It
#1494 posted by ijed [190.22.91.72] on 2014/07/23 15:39:04
Stupid mistake in walkmonster_start
#1495 posted by digs [94.41.18.121] on 2014/07/28 10:48:19
Can I make a recursive function? What is the maximum stack depth?
 Recursion
#1496 posted by Preach [77.98.165.95] on 2014/07/28 12:34:53
You can create a recursive function, the maximum stack depth is 32. This is possible to hit, see http://tomeofpreach.wordpress.com/2013/08/09/going-overboard-with-field-pointers/ for an example and a bit more detail.
Spike posted a warning somewhere on here that local variables to a recursive function are not reset between calls. So you should initialise all your variables like you would in C when writing a recursive function, rather than assume they get initialised to zero.
 @Preach
#1497 posted by digs [136.169.205.73] on 2014/07/28 15:33:42
Thanks. 32 is very small for my task. I'll have to think of something else
#1498 posted by digs [136.169.205.73] on 2014/07/28 15:52:44
How much time can be in progess the function? Can the engine to break it off if it is too long time?
 Instruction Limit
#1499 posted by Preach [77.98.165.95] on 2014/07/28 22:56:55
The engine does have a limit, not strictly on time spent, but on number of instructions. You can only run 100,000 instructions in a single think, touch, spawn (etc) function before the QC concludes that there's a runaway loop and the engine packs it in.
#1500 posted by Spike [86.166.68.155] on 2014/07/29 01:37:14
regarding locals getting clobbered in recursive functions, you can try '#pragma warning enable F302' to get fteqcc to print warnings when it detects that locals were not initialised before use.
fte/dp have a higher limit than 32.
you can get around the instruction limit by splitting up your routine into multiple thinks. in general your mod will be unplayable if you do not do this in the first place due to the stalls induced by running the qcvm.
in fte, there's some obscure 'sleep' builtin which will defer the current invocation/coroutine until a later time. doing this will preserve locals but not globals/fields. the instruction limit will be reset in the process. hurrah for infinite loops that won't lock up the game. just make sure nothing is harmed if some other think or whatever function removes the entities in the mean time...
 Preach
#1501 posted by necros [99.227.110.3] on 2014/07/29 01:47:48
I thought it was 100000 instructions per frame.
 Reset The Counter
#1502 posted by Preach [77.98.165.95] on 2014/07/29 20:04:35
You get a new counter every time PR_ExecuteProgram is called, which means every time the engine calls a QC function of some kind.
They can even nest - suppose you are in a monster's think function, and use 50000 instructions before you call walkmove and collide with a player. You get a new lot of 100000 instructions to run the monster's collision function, then yet another set of 100000 to resolve the player's collision function, THEN you go back to the think function and get the remain 50000 instructions to wrap up there.
#1503 posted by necros [99.227.110.3] on 2014/07/30 00:50:40
ohhhh, nice to know i was being overly conservative then. this is like finding 20$ in my couch!
 Parsing Texture Names In QC
#1504 posted by Qmaster [70.195.66.168] on 2014/07/30 22:19:31
Is it possible to return a string to a function that does traceline and returns the texturename of the wall that traceline hits. I understand that the entity returned would be world, but is it possible to get the texture name from the bsp surfacr? Like "brick2_4"?
 Nope
#1505 posted by Lunaran [216.188.254.244] on 2014/07/30 22:31:36
#1506 posted by metlslime [159.153.4.50] on 2014/07/30 22:37:50
probably darkplaces has this.
 Darkplace Does
#1507 posted by Preach [77.98.165.95] on 2014/07/30 23:05:06
Check for extension DP_TRACE_HITCONTENTSMASK_SURFACEINFO
Then you can define:
string trace_dphittexturename;
then when you do a standard traceline, the texture name gets assigned to that variable.
One of the nice properties here is that there's no extra built-in function involved, so the code is very easy to make safe in engines which don't support the extension. In those engines, the texture name will always be "". So you can do stuff like special footsteps or impact particles on particular textures, and the other engines will gracefully degrade to the defaults for free!
 Example Using DP
#1508 posted by sock [190.231.85.129] on 2014/07/30 23:16:03
//----------------------------------------------------------------------
// Check for contact with sky brushes
//----------------------------------------------------------------------
float(vector targ_origin) check_pointcontent =
{
local float surfnum;
local string texturename;
surfnum = getsurfacenearpoint(world, targ_origin);
if (surfnum >= 0) {
texturename = getsurfacetexture(world, surfnum);
if (strncasecmp(texturename, "SKY", 3) == 0) return TRUE;
}
return FALSE;
};
 The Same Function Without DP
#1509 posted by Preach [77.98.165.95] on 2014/07/30 23:56:19
float(vector targ_origin) check_pointcontent =
{
return (pointcontents(targ_origin) == CONTENT_SKY);
}
 @Preach
#1510 posted by sock [190.231.85.129] on 2014/07/31 00:05:53
The latest version of DP does sky pointcontent detection different, hence the function, but a working example of detecting surface information can be adapted for what Qmaster wanted. ;)
 <--the Icon Intended For The Last Post
#1511 posted by Preach [77.98.165.95] on 2014/07/31 00:29:41
nt
 Cool
#1512 posted by Qmaster [50.40.182.176] on 2014/07/31 01:32:59
As ever yall are awesome. Thank you!
 Okay Then.
#1513 posted by Qmaster [50.40.182.176] on 2014/07/31 02:34:54
That one was too easy for the masters. Here's a real stumper for you.
I want to simulate a halucinagenic side-effect for one of my power-ups in game. Here's how I want to achieve it, in psuedo code:
float TRIPPY_EFFECT_INTERVAL = 5.000 //5 seconds
// string "gfx/palette_trippy1.lmp"
// string "gfx/palette_trippy2.lmp"
// string "gfx/palette_trippy3.lmp"
void () trippydrug_think = {
if (trippydrug > FALSE)
{
setpalettefile("gfx/palette_trippy", trippydrug, ".lmp");
trippydrug++;
self.owner.trippy_power = (trippy_power * 2)
self.think = trippydrug_think;
self.nextthink = (time + TRIPPY_EFFECT_INTERVAL);
}
};
The 1st palette file will have the colors shifted over 4 colors so most things are similar to what they should be, then mixed up a little bit in the 2nd, with the 3rd palette file looking like crayola barf making it hard to see.
So... I can't find out how to change the palette on the fly within the engine code? I can override palette.lmp in the gfx folder, but... more than once, during runtime...?
#1514 posted by Spike [86.166.68.155] on 2014/07/31 12:40:30
host_basepal or something stores the palette.lmp file in memory. mix that up with the "bf" command to figure out how the engine applies a new palette in a software renderer. or something.
in gl renderers things get much more messy, figure that one out on your own, if you dare.
 Ooh Goody
#1515 posted by Qmaster [70.195.66.168] on 2014/07/31 16:32:53
Its like a treasure hunt!
 Question On QC Syntax
#1516 posted by Preach [77.98.165.95] on 2014/08/02 17:49:54
I've got two questions, and I suspect that spike might be able to answer for fteqcc if nobody else can.
1) Is it possible in QC to have a function that returns a function - and if so, what is the syntax for that?
2) If 1) is possible, I would like a function that can return itself (or other functions with the same signature as itself). Is this possible, and how?
#1517 posted by Spike [86.166.68.155] on 2014/08/02 18:51:08
if in doubt, typedef it.
typedef void() fnc;
fnc bar = {}; //or: void() bar={}; depends which you consider more correct/easier
fnc() foo = {return bar;};
void() test = {local var fnc t;t = foo();t();};
foo()(); isn't supported for some reason.
nor is void()(). bah.
seems the return statement doesn't do strict checks beyond basic types, must fix some day.
needing to define a local function as var is also worrying, one day I'll want to be able to define functions inside functions, I believe it should be possible to parse nested functions automatically, but I'm paranoid enough to not fix that until then.
on the plus side, void()foo()={return bar;}; also works! yay for mixing notation.
a function that returns itself ad infinitum is problematic. probably best to define the function as returning a __variant, seeing as you'll need to store it anyway before you can call it. qc can then suffer from the infinite type recursion itself. :P
I'm not sure what the advantage is though.
 Cool
#1518 posted by Preach [77.98.165.95] on 2014/08/04 22:25:38
Thanks for that, the plan is to do some contination-passing, state machine stuff. Thinking it might be easier to use a global rather than passing a return value, but the __variant trick would probably make it work...
 Quake Web Tools Progress
#1519 posted by than [182.164.203.103] on 2014/08/05 11:43:00
http://pecope.co/experiments/quake_web_tools/QuakeWebTools.html
I haven't really been working on this until the last couple of days, so it hasn't changed that much, but I added camera controls to the MDL viewer and you can now preview BSPs in 3d (though there is no lighting currently) with first person controls.
Seems to handle anything I throw at it too, which is surprising. Thought it would be easier to break :)
Anyway, I'm still planning to implement a proper UI at some point, but I have been concentrating on core file type support, which is about done now, but there is still a lot of cleanup that needs doing.
#1520 posted by Lunaran [99.112.162.57] on 2014/08/05 17:00:54
in firefox the 3d panel doesn't capture keyboard input without bubbling it back to the browser, so when I try to hold w to move forward in a map the search bar appears and fills with wwwwwwwwwwwwww and then I lose the bsp forever in the darkness
I fed it a few jam2 maps and it seemed to like them, but I got to jam2_tronyn and a number of faces have flat colors or skewed stripes instead of properly projected textures.
 Reposting For Coder Help
#1521 posted by necros [142.245.59.11] on 2014/08/05 20:18:39
Aguirre's TXQBSP:
Error: NewWinding: 65 points?
After piles of healing point of plane warnings.
Tried using different epsilon values, but nothing gets rid of the error.
#1522 posted by mfx [78.49.222.121] on 2014/08/05 21:50:52
Guessing in the dark i am.
Too many faces share the same plane?
 Ok
#1523 posted by mfx [78.49.222.121] on 2014/08/05 22:24:42
here what i got after talking to rebb.
There a hardcoded limit on MAX_POINTS_ON_WINDING
of 64 in TXQBSP. This "should be enough".
One can replace that with a dynamic array, resulting in performance loss.
Anyway, QBSP isn´t the deal here, vis does this check too. Again longer vistimes are the result(~ factor of 1.5 with a small testmap).
 Oh God My English
#1524 posted by mfx [78.49.222.121] on 2014/08/05 22:26:13
Necros, there are testbuilds available at http://www.voidspark.net/projects/bjptools_xt/
soon..
 One More Thing
#1525 posted by mfx [78.49.222.121] on 2014/08/05 22:31:36
rebb told me: those limits could just be raised in the codebase, but there are dangers of stackoverflows. Even today?
idk tbh
 Well
#1526 posted by rebb [91.35.101.111] on 2014/08/05 23:33:39
It's probably safe to bump that limit to at least Half-Life compiler level where it's 128 instead of 64, and stack limits can be increased when compiling the compiler. The whole thing is meant to be a performance-optimization that matters mainly for Vis calculation times.
#1527 posted by necros [99.227.110.3] on 2014/08/06 03:40:34
thanks for helping me understand this mfx/rebb.
So yeah, the latest test version lets the map compile but what exactly is this winding stuff?
From what I remember when I briefly dabbled in 3D and openGL stuff, winding is some kind of method of storing your vertices and faces in memory...
I guess I'm asking how can I avoid doing this?
Too many faces share the same plane?
I think someone once said that there is a limited number of planes than can be used in one map, but that if you have faces with the same plane, it'll reuse that plane or something..?
Also rebb: texture offset for rotating objects!!!!!!! <3
 Lunaran
#1528 posted by than [182.164.203.103] on 2014/08/06 04:18:37
Thanks for the feedback. I haven't really tested in multiple browsers yet, but I'll check that out next time I work on it.
Not sure how I can fix the texture problem though, I noticed that myself but since the uvs are just generated from the bsp data I have no idea what is causing the problem. There are also some limitations with webgl, so any non-power of two textures could potentially cause problems depending on the system.
The bsp preview isn't really meant as an accurate bsp viewing tool though. Would be nice to add lightmaps and have a few display options though.
 @than
#1529 posted by Spike [86.182.96.207] on 2014/08/06 05:35:09
extensions appear to be case-sensitive, meaning it'll refuse to load files copied off a fat32 drive (FOO.BSP).
no error message from trying to load q3/rbsp/bsp2 maps.
clicking files within a .pak doesn't seem to do anything (firefox).
it doesn't recognise .qc!
mdl rendering consumes an entire cpu core even when not given user input.
 Spike
#1530 posted by than [182.164.203.103] on 2014/08/07 01:56:39
thanks. I'll look into all those things.
Not sure what I should do with .qc files... What would you like it to do?
Firefox doesn't seem to handle the file url the same as chrome, since I'm not generating a data url until the user clicks a link, which basically equals me auto downloading a generated file for the user - perhaps it's a security risk? Anyway, chrome allows you to extract files currently, but I want to make it able to modify paks at some point.
Anyway, it's currently very hacky (esp. rendering), so I will fix some of this during the next code cleanup.
 Also Rebb: Texture Offset For Rotating Objects!!!!!!!
#1531 posted by Nurax [78.55.198.30] on 2014/08/08 03:17:21
Thanks a lot for this rebbor!!
 Necros
#1532 posted by Preach [77.98.165.95] on 2014/08/09 02:26:34
I have a vague recollections that windings are to do with the number of sides a polygon has. Do you possibly have a face anywhere with more than 64 edges? Perhaps not intentionally, but if you had lots of adjacent planes that nearly meet at the vertices but actually cut tiny slices, that might create one....
#1533 posted by necros [99.227.110.3] on 2014/08/09 05:04:16
I'm not exactly sure what you mean. How could a face have 64 edges? They are all triangles. Or do you mean one plane that has been divided more than 64 times?
 The Bsp Is Actually Made Of Polygons
#1534 posted by ericw [199.126.128.107] on 2014/08/09 05:39:33
In fact in glquake they're still polygons when passed to OpenGL. Just for fun I checked start.bsp and it has a 20-sided poly somewhere!
So "r_showtris 1" is a bit deceptive; it shows you the polygons as they come out of the bsp, plus a bunch of lines drawn in to divide them into triangles, but you can't see which lines are which.
#1535 posted by metlslime [76.103.211.139] on 2014/08/09 10:42:12
r_drawflat shows polygons.
#1536 posted by rebb [91.35.82.221] on 2014/08/09 13:10:52
Windings are used in a lot of places in the code, also for portal generation. I think mfx managed to find a version of your map in your house while you were sleeping online and it had a very large ring-like structure in it with a lot of side elements.
If a portal is generated inside this, it can easily go over the 64 point limit and cause this error to be thrown.
 Necros
#1537 posted by SleepwalkR [80.187.106.200] on 2014/08/09 14:16:40
Breaking limits since 2003!
 Another Workaround
#1538 posted by Preach [77.98.165.95] on 2014/08/09 15:07:27
Once you've found places where that happens, shouldn't it be possible to use a hint brush to break that ring in half/quarters/etc so that can't happen?
 Heho
#1539 posted by mfx [92.229.98.70] on 2014/08/09 17:40:13
Necros, the file flew by on the TB issuetracker, had to grab it to reproduce the error.
I also had no luck with epsilon values being changed slightly, but the hint/skip support of the above mentioned compilers should be able to eliminate the error.
Without having to raise the max_windings of course.. I keep you updated.
Sorry for any inconvience caused:)
#1540 posted by necros [99.227.110.3] on 2014/08/09 17:41:59
Cool, ok, so it is fixable then... Yet flying around in the map didn't show me anything obviously having tons of edges. Some faces had maybe 6 or 7 sides, but most were split up to 4 or less sides.
and it had a very large ring-like structure in it with a lot of side elements.
Not sure which map you're talking about, but this is a new one with a very similar concept. It is a large ring of windows. So since I don't see any faces with a lot of edges, it sounds like it must be this case where a portal is being generated inside this ring.
 Demo Smoothing
#1541 posted by Mandel [80.217.81.214] on 2014/08/09 20:09:19
I've built a demo smoothing utility for DaZ, and even though I suppose it's of limited use, I'll post it here anyway in case anybody is curious and in order not to give any particular youtubers any unfair advantages!
http://mandelmassa.net/quake/demsmooth-1.02.zip
The binary is a 32 bit Windows build made with mingw32-gcc in cygwin. Source is here:
https://github.com/mandelmassa/demsmooth
#1542 posted by necros [99.227.110.3] on 2014/08/09 22:00:29
this is the method used to get the smooth camera movement?
#1543 posted by Mandel [80.217.81.214] on 2014/08/09 22:13:15
I think DaZ has used it in some of his latest Quake videos, for the intro bit. That's what it's intended for! Using it on regular play demos might render unexpected results since it's tuned for slow movement.
#1544 posted by FifthElephant [82.24.73.240] on 2014/08/09 22:17:13
I just converted one of my normal play demos with it and it looks like I'm drunk or stoned playing.
 Actually
#1545 posted by Mandel [80.217.81.214] on 2014/08/09 22:41:58
It was made in response to the now classic january 1st W00tles post!
 Mandel
#1546 posted by necros [99.227.110.3] on 2014/08/09 23:04:54
That's a very cool utility! I thought he was placing waypoints or somesuch, but this method of doing a flyby camera is way more intuitive and simple!
 Demo Smoothing 1.03
#1547 posted by Mandel [80.217.81.214] on 2014/08/14 18:44:58
Fixed a bug with parsing Fitzquake spawn baseline messages - the program couldn't parse my own jam2_mfx demo so I just had to debug it.
http://mandelmassa.net/quake/demsmooth-1.03.zip
#1548 posted by Spirit [92.196.26.211] on 2014/08/14 19:18:16
Mandel, please write Quaddicted a demo meta data extraction tool for 15, 10002 and 666. Something that extracts statistics like kill/secret count, length, completion, skill, maybe even shots fired or distance tracked if that is possible. Thank you! bye!
#1549 posted by Mandel [80.217.81.214] on 2014/08/14 19:35:10
I just might!
#1550 posted by Lunaran [99.112.162.57] on 2014/08/20 05:52:43
In triggers.qc:
void() teleport_use =
{
self.nextthink = time + 0.2;
force_retouch = 2; // make sure even still objects get hit
self.think = SUB_Null;
};
the purpose of force_retouch is clear, but I've always wondered why a teleporter had to have its nextthink set just to do nothing. Is that more obtuse secret qc behavior related to how force_retouch works? Or just cruft?
 @ Lunaran
#1551 posted by Spike [86.140.27.59] on 2014/08/20 07:25:39
beware of force_retouch! it breaks trigger_hurt!
anyway, the touch function:
if (self.targetname)
if (self.nextthink < time)
return; // not fired yet
it uses nextthink as a random timer for some reason. just weird code. there's no special engine magic needed here, just the sub_null thing to stop the engine complaining when it does try to do its think magic.
it should have used attack_finished...
 Force_retouch
#1552 posted by ijed [200.73.66.2] on 2014/08/20 14:35:07
Has caused me a load of headaches - a lot of the code I ported used it in loops, some of them per frame (!) which was raping FPS.
 Oh, Duh
#1553 posted by Lunaran [99.112.162.57] on 2014/08/20 16:49:14
 Yeah
#1554 posted by ijed [200.73.66.2] on 2014/08/20 17:12:08
Not sure what the intention was with a lot of them.
One in particular was causing a batch of triggers to touch themselves every single frame, meaning the more of that type of trigger I had, the slower it got.
#1555 posted by Lunaran [216.188.254.244] on 2014/08/20 21:50:57
I meant "duh" to the answer to my question, since I could have just looked at teleport_touch and noticed it myself without having to ask anyone.
Some people just write code in incredibly bizarre fashion. They get fixated on entirely the wrong approaches and then use them for everything. I wish I remember what game it was, but some high profile indie game's source was available on pastebin or one of those, and it was an astoundingly bad clockwork machine of almost 100% string manipulation, in one huuuge header file. Maybe someone else remembers?
 Sounds Like Minecraft
#1556 posted by czg [85.224.36.170] on 2014/08/20 22:26:34
But probably wasn't.
#1557 posted by JneeraZ [174.97.226.218] on 2014/08/31 17:51:32
Hey, so ... Is there an easy way in QuakeC to determine that the player has seen an entity for the first time? Like, an ammo or health pickup for example?
#1558 posted by necros [99.227.110.3] on 2014/08/31 20:17:50
hmmm not exactly.
you COULD just make a function call that continously runs every frame that checks all entities and marks any items it finds as seen, but that's pretty wasteful and might even cause slow down if there are enough entities in the loop.
Alternatively, you could create a one time, on map load function that builds a new list of only items and then the previously mentioned loop could only iterate through that list.
A simpler, but more manual method would be to just have triggers that mark entities as 'seen'.
This is the method I used in ne_ruins for a few ammo boxes. They are dynamically changed between small or large when the trigger fires on them but only once, so if the player has triggered the check when they had a lot of ammo and the boxes are small, they won't become large boxes later if they revisit the area with low ammo.
#1559 posted by JneeraZ [174.97.226.218] on 2014/08/31 23:47:52
Yeah, that's what I wanted to do ... dynamically scale health and ammo to the players needs. But I guess I won't. That sounds like a lot of trouble and really too much work for what it is...
Thanks!
#1560 posted by metlslime [159.153.4.50] on 2014/09/01 00:19:07
just have a crate you break open to get the item -- you can decide what item to spawn once the crate breaks.
Or have items drop off enemies, and scale the amount based on player's current needs.
#1561 posted by metlslime [159.153.4.50] on 2014/09/01 00:19:07
just have a crate you break open to get the item -- you can decide what item to spawn once the crate breaks.
Or have items drop off enemies, and scale the amount based on player's current needs.
 Func_fail
#1562 posted by metlslime [159.153.4.50] on 2014/09/01 00:19:28
#1563 posted by necros [99.227.110.3] on 2014/09/01 00:27:54
on your own board, no less!
I prefer using triggers to decide rather than crates because it feels like it creates a better illusion.
#1564 posted by metlslime [159.153.4.50] on 2014/09/01 00:32:14
the trigger thing seems pretty easy as long as you aren't running out of edicts. Just place one trigger in the previous hallway to spawn the item.
#1565 posted by JneeraZ [174.97.226.218] on 2014/09/02 01:17:53
So before I write it, has there ever been an OBJ to MAP convertor written? There had to have been, right? I'd love to use MODO to generate geometry that is downright tedious or impossible in Trenchbroom...
#1566 posted by Spike [86.183.27.238] on 2014/09/02 03:26:45
Sharkbanana who can sometimes be found in #qc had a tool for generating q3 .maps that way. I don't know if he wrote it or got it from elsewhere.
it didn't seem to be worth it. too many precision issues or something. tbh, just use misc_model, but then this is q3bsp that I'm talking about, where that sort of thing is possible.
 Willem
#1567 posted by Lunaran [99.112.162.57] on 2014/09/02 03:53:25
why don't you have the relevant items .think and call checkclient()? That's certainly not too slow for every monster in the level to call ten times a second.
#1568 posted by necros [99.227.110.3] on 2014/09/02 06:16:55
ohh yeah, actually that makes way more sense.
checkclient is pretty quick since it's a built in and uses pvs.
#1569 posted by Lunaran [99.112.162.57] on 2014/09/02 07:23:21
you'll have to filter newly awakened monsters, because they count as clients for one frame to propagate aggro through crowds, but that's simple enough.
 Checkclient
#1570 posted by metlslime [76.103.211.139] on 2014/09/02 07:38:51
sounds like a pretty good solution.
 Monster Behaviour
#1571 posted by madfox [84.26.177.181] on 2014/09/07 05:57:11
I have finished the mr.big model, a rocket jumping, and heavy weapon entity.
Looking in the hknight.qc for the magic to give the gun a "spread" fire action, and in the dog_leap routine for the rocket jump.
The heavy weapon now results in such a damage that even its own entities get killed when placed in the same surounding.
I thought there was a line of code in the ogre.qc that provided this behaviour, not killing own enemy.
Also
SV_startsound:not precached.
How to avoid it?
#1572 posted by necros [99.227.110.3] on 2014/09/07 06:49:23
SV_startsound:not precached.
you forgot to precache a sound you're using, check all the sound() function calls for any you missed.
not sure about the self damaging, that could be many things. the most obvious thing to check for me would be that you are passing the right entity for the ignore argument in t_radiusdamage. For example, usually it's self.owner, so make sure you set the missile's .owner field correctly.
 MrBig
#1573 posted by madfox [84.26.177.181] on 2014/09/07 08:15:10
thanks necros. I did check the sounds, but strangly only the second monster's call gives the warning.
For convienence, here 's a testmap for MrBig. The qc is included.
#1574 posted by necros [99.227.110.3] on 2014/09/07 17:20:52
it's the sight sound. that's the only sound that is played outside of the monster's qc file... check ai.qc for the SightSound() method to see which sound is being played.
 Ai.qc
#1575 posted by madfox [84.26.177.181] on 2014/09/07 23:38:56
Searched the qc.file, but what I find is in void() FoundTarget, what I believe as local float rsnd;.
Is that the spot for SV_StartSound<q/>?
#1576 posted by Lunaran [99.112.162.57] on 2014/09/08 01:23:07
madfox, ogre grenades can totally kill nearby monsters, it just has such a small weak explosion compared to player explosives that it rarely ever does (dmg is 40, radius is dmg+20). It's not even strong enough to kill a zombie.
 Unsound Reasoning
#1577 posted by Preach [77.98.165.95] on 2014/09/08 01:43:17
Ah, here's where the confusion is
SV_StartSound is in the engine, don't go looking for that in the QC. The part of the message you need for debugging is where it tells you which sound wasn't precached. If you like, you can then look through the QC for that sound to find out which bit of code is trying to play it. Really though, you don't have to know who wants to play the sound, just precache it in your monster's spawn function so it stops being an error.
 Kanguru Ogre
#1578 posted by madfox [84.26.177.181] on 2014/09/08 05:28:12
@Lun - sure, but this is no ordinary ogre, it is carying an old fashion 8-loop gun and can flush a spread shot of 20 spikes within 20frames.
I lowered it to 8 on 20fr.
That's a lot of damage, see the test file.
@Preach - can't find it in the qc file, precached all sounds. It might be the player's sound is missing but that's loaded in world.qc.
Is there a console command for this tracing not precached?
 Get Server To Recognise That Temp1 Has Been Set By Client?
#1579 posted by slackhead [82.44.71.14] on 2014/09/12 06:14:35
Is it possible in quakec for a client to set temp1 via a console command or alias, and have the server see that and act on it? Not having much luck so far.
I have a function that watches temp1 for change and echoes a simple message, and the call for that function is in StartFrame() in world.qc but it isn't picking anything up.
 Holy Security Risk, Batman!
#1580 posted by Spike [86.166.67.218] on 2014/09/12 11:59:18
use impulses or krimzon_sv_parseclientcommand.
#1581 posted by slackhead [82.44.71.14] on 2014/09/12 17:14:41
Thanks a lot. krimzon_sv_parseclientcommand is exactly what I need :)
 Var On FTEQCC And Save Games
#1582 posted by Preach [77.98.165.95] on 2014/09/13 04:27:32
So in FTEQCC you can use var to make a global function pointer which can be changed, which is very cool. I was worried earlier on when poking around in the text of a save file that I couldn't actually see an entry for this variable. Now I've managed to actually hit a point where loading a save game causes a "null function" crash to console (hitting the same trigger without loading a save first worked fine).
At the moment the variable in question is storing state which can't be deduced from the rest of the world when the save game loads. This rules out a fix using the LoadGame function to repair the damage. So far I've not managed to think of a better workaround than allocating an entity and storing the function in there. Is this a fundamental limitation of the save game parser - that it's not built to read functions into globals? Is there anything smarter I can try?
 Additional
#1583 posted by Preach [77.98.165.95] on 2014/09/13 10:49:28
Posted that late at night, in the morning I realised that there was one thing I could test...
The test involves my favourite trick of late, editing the save game that lead to the bug in your text editor. If you add a line "default_monster_spawn" "monster_shambler", the game parses it correctly and the bug goes away. So it's not the loading of the save game that lacks the support. I'll revise my guess that it's the saving of the save game that doesn't support this...
#1584 posted by Spike [86.166.67.218] on 2014/09/13 15:57:35
found in vanillaish pr_edict.c ED_WriteGlobals:
if (type != ev_string
&& type != ev_float
&& type != ev_entity)
continue;
Blame the engine.
 OK, As Suspected
#1585 posted by Preach [77.98.165.95] on 2014/09/13 21:35:09
Well, I think I've thought of a not-terrible way to fix up the missing data when a game is saved in this particular case. Must write all this up into a blog post or something though.
 Blog Post
#1586 posted by Preach [77.98.165.95] on 2014/09/28 18:16:19
Just in time to make it so that there are blog posts for this month, a new coding article. This week: the Factory Pattern.
http://tomeofpreach.wordpress.com/2014/09/28/the-factory-pattern/
Use it to spawn clones of entities, reset your map cleanly between rounds and ...prevent map hacks? What blasphemy!
#1587 posted by JneeraZ [174.109.106.46] on 2014/09/29 14:08:13
Preach got me interested in Python so I spent time learning how it works and converted my OBJ2MAP C# utility to it. Python is probably going to be my utility language going forward - so nice to work with!
https://dl.dropboxusercontent.com/u/161473/SeptQuake/PythonVictory.jpg
 Python Fucking Rules
#1588 posted by Lunaran [216.188.254.244] on 2014/09/29 23:34:40
#1589 posted by RickyT33 [176.35.71.152] on 2014/10/02 12:42:58
 Peak Ballmer
#1590 posted by onetruepurple [93.105.236.164] on 2014/10/02 12:52:27
 CSQC: Talking To The Server
#1591 posted by Qmaster [50.40.173.156] on 2014/10/06 03:31:52
It can sometimes feel convoluted to communicate with CSQC and the server, sending entity data back and forth. I'm going to summarize some things here to help people out, but also so that I can help myself learn about them. When you can teach something, you understand it and have to learn more about it than those you teach.
There are currently three methods that I'm aware of to send data to CSQC:
Console variables, AddStats, and CSQC_Ent_Update
There are currently these methods that I'm aware of to send data from CSQC to the server:
Console variables, SV_ParseClientCommand
Console variables seems fairly straightforward. Advantages: Able to be keymapped, Able to be accessed by the player via the console or config file, simple to code, two way street
Disadvantage: Able to be accessed by the player (cheats!), Only useful for a single variable (floats, strings, vectors)
AddStats is basically the same as a console variable but only visible to CSQC, and automatically updated whenever the variable in server QC is changed. This is great for ammo and health since these are simple float values.
Advantages: Simple to code, auto-updating
Disadvantages: Only useful for a single variable, One-way sending of data to CSQC (CSQC can't change it, only read it)
SV_ParseClientCommand is a beautiful thing. This function is what is called anytime someone types in text into the console and hits [ENTER]. CSQC can call it by using a localcmd ("cmd ",yourvariable.here,yourvariable.here2,"n"); You can actually override all cheats by having void (string cmd) SV_ParseClientCommand = {/*clientcommand(self, cmd);*/};, (note the /**/ commenting out the important part, if you forgot to add this line at the end of your client command function, you may be wondering why all your cheats aren't working...oops! learned that the hard way)
Advantages: Powerful and can be used to send multiple data variables at once from CSQC to server QC
Disadvantages: A bit complicated to set up, one-way from CSQC to server QC.
Finally, CSQC_Ent_Update is the most confusing one of all, but potentially the most powerful way to send data to CSQC. Updating an entity requires the server entity to have float() .SendEntity function that is called by the engine everytime that entity's .Version field is changed. Typically, like this: entity.Version++; The SendEntity function needs to WriteByte (or String or whatever) for each variable it sends. This needs to match each ReadByte (or Readwhatever) in the CSQC_Ent_Update function.
Advantages: Powerful, can send multiple variables at once to CSQC (practically sending an entire entity to CSQC)
Disadvantages: Complicated, confusing, easy to break or make buggy.
The most confusing thing for me is that CSQC_Ent_Update is called...um...shoot. I dunno when it's called. Immediately when the entity's .Version is modified in server QC, i.e. mid-frame? at the end of the server frame does the engine check all entity's versions and then call CSQC_Ent_Updates sequentially? Is Darkplaces's implementation different than FTEQW's?
What is the order anyways? In one frame, is server code carried out first, then CSQC code? Or CSQC first?
Who knows...CSQC isn't that popular so the all the basic concepts for it communicates with QC isn't defined anywherer in so explicit an article. There are snippets here and there but no one place has all the data. Hopefully this brief summary can help someone.
#1592 posted by Spike [86.135.168.123] on 2014/10/06 13:18:26
A couple of things to note.
1: .Version is outdated, you shouldn't use it, instead set self.SendFlags |= 1; or whatever and the engine will tell you what flags were set since the client last received a copy of the entity.
2: CSQC_Ent_Update is called 'whenever'. There is no specific time documented because an update can be lost or queued. Network latency is also a factor. If you depend upon ordering then you loose. If the entity gets removed in ssqc before the message was sent (due to packetloss triggering constant resends) then it can be lost entirely, otherwise packetloss will merely trigger a resend. Not every version is guarenteed to be sent, the server sends when it knows there's something pending and when it feels like it. It has lower latency than reliable messages (as it doesn't depend upon previous reliables to be acked first), but does not guarentee anything but the most recent update (like stats).
3: it is possible to send messages directly to csqc. either via temp entities (dp), or via svc 83 (fte, must be multicast). Beware of illegible server messages, you can try sv_csqcdebug in fte to diagnose these, assuming they're caused by QC.
4: fte has a sendevent builtin that can send csqc->ssqc messages.
5: deltalisten(fte) or getentity(dp or fte) can be used to read various bits of an entity without needing special sending/parsing.
6: using cvars to send stuff to csqc is horrible, and is impossible for csqc->ssqc (no server exploits please).
7: csqc can directly parse centerprints(CSQC_Parse_CenterPrint), stuffcmds(CSQC_Parse_StuffCmd), or sprints/bprints(CSQC_Parse_Print). its the equivelent to SV_ParseClientCommand, but the the other way around.
 Brilliant Stuff Spike!
#1593 posted by Qmaster [50.40.173.156] on 2014/10/07 00:24:30
Now if someone had time to update: http://quakewiki.org/wiki/EXT_CSQC#Sending_Data_to_the_Client
:) Maybe when I'm finished with my project in a couple months I'll update that page.
 Returning Null...
#1594 posted by necros [99.227.110.3] on 2014/11/01 21:52:33
in c++
So, in java, you might do something like this:
class Foo
{
int a;
int b;
Foo(int x)
{
a = x;
b = x;
}
}
Foo getFoo(boolean z)
{
if (z)
return Foo(5);
else
return null;
}
So you'd get a pointer to a new Foo object or not depending on the argument z. This is nice.
But what about in c++? The Foo class is tiny, and it would be best to return it by value. But if we wanted to return null, this isn't possible anymore.
Is the only solution to that really this:
bool getFoo(boolean z, Foo& f)
{
if (z)
{
f = Foo(5)
return true;
}
else
{
return false;
}
}
#1595 posted by necros [99.227.110.3] on 2014/11/01 21:53:10
granted, you could return pointers to new objects on the heap, but then you've got to delete them after which is a pain.
 Necros
#1596 posted by SleepwalkR [85.178.62.176] on 2014/11/01 22:49:10
I shall preface this with a quote by Tony Hoare:
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
Don't abuse null as a special return value indicating that nothing could be returned. It's really bad style (I do it all the time though because it's easy - go figure).
There are several ways to avoid null in this scenario:
1. Provide a method that checks whether a result will be available before you invoke your get method. There is a name for this idiom, but I can't remember it right now. It's basically like this:
bool canFoo(int x);
Foo getFoo(int x);
In getFoo, write an assertion that canFoo is true to detect bugs in debug mode.
However, this has the disadvantage that any logic that determines whether a return value is available may have to be executed twice: Once in canFoo and once in getFoo when the value is computed.
2) Create a default instance of Foo that is always returned when no value is available. This instance might even be able to behave in a sensible way, maybe displaying an error message when some of its methods are called.
3) Return a std::pair<boolean, Foo> where the first element indicates whether a result was available or not. This is basically the same as returning NULL from the method when you use pointers, but it makes the calling code a bit uglier because the syntax to access the elements of std::pair is a bit awkward. I sometimes write my own wrappers instead of std::pair for this.
Personally, I will use of these options in the order I presented them, so 3 is a catch-all that I'll use if 1 and 2 are not feasible. In either case, you put the burden of checking whether a result exists on the caller, but that's no worse than using NULL.
Side note: Some languages such as LUA allow you to return more than one value from a function. I consider this the best solution because you can write something along the lines of
bool valid, Foo foo = bar.getFoo(5);
if (valid) { ... }
#1597 posted by necros [99.227.110.3] on 2014/11/02 01:20:22
I notice you didn't have my own suggestion in your list above... Is there something wrong with passing a reference that you will store the actual result in to the function? I figure, as long as you're careful with your const declarations, there shouldn't be any danger of accidentally mangling anything important.
 I Don't Like Out Parameters
#1598 posted by SleepwalkR [92.231.224.38] on 2014/11/02 08:42:22
And I try to avoid them where I can. That's why. Also if you know that your Foo need not be changed, you should make it const, but you can't with your approach because getFoo cannot take a const reference.
#1599 posted by necros [99.227.110.3] on 2014/11/02 17:46:17
Ah ok, I would use it more for short live temporary things anyway.
Something you'd create on the stack before calling the method, then read what you got back if the method returned true (and ignore it if it was false).
using a pair seems like the least hacky and most efficient way of doing it otherwise.
method #2 means you either need dummy values which you need to know mean the object is garbage or you need to include a boolean value into the class that you can check to see if the data is good or not, but that boolean may not always be relevant.
method #1 is good, but you might be doing a check twice, or some steps needed to check in canFoo() might be used to do the work in getFoo() so at the least you can be repeating some steps.
Anyway, thanks for your input. I am starting to really warm to this language!
 Constness
#1600 posted by SleepwalkR [92.231.224.38] on 2014/11/02 18:32:47
I am a total const nazi. Every variable / parameter that can be const, should be. The same goes for member functions. This is the best feature that C++ has over Java, in my opinion. I would really suggest that you become a const nazi too, because it leads to cleaner code if you give some thought about whether a function can have side effects or not, and functions without side effects are much safer!
You're right about option #2 - it's seldomly applicable, but when it is, it works very well and leads to cleaner code because the caller doesn't have to worry about whether the return value is valid or not.
#1601 posted by Johnny Law [67.188.146.229] on 2014/11/02 18:35:18
I appreciate languages like Python and Erlang that allow you to naturally return arbitrary tuples from functions. Or that are dynamically typed so that you can just return a special error token from a function that would normally return some other type.
I'd probably go with solution 3, since another gotcha with method #1 is that there's a race window between checking and fetching the data (if the data is mutable).
 Only If There Are Concurrent Threads.
#1602 posted by SleepwalkR [92.231.224.38] on 2014/11/02 20:33:35
But yeah, that's true.
 Random Weirdness
#1603 posted by necros [99.227.110.3] on 2014/11/02 22:06:04
Interesting bit...
if you forward declare a class, you can use a pointer.
if you don't include the header for that class, when you call delete on the object, it silently fails to run the destructor.
that had me stumped for a while...
 Clang Has A Compiler Warning For This.
#1604 posted by SleepwalkR [92.231.224.38] on 2014/11/03 00:03:18
Be sure to enable all compiler warnings you can. It will safe you a lot of headaches.
 Monster_friend
#1605 posted by madfox [84.26.177.181] on 2014/11/13 00:38:12
I made a zombie friend, that does escort the player and, as long as the player doesn't shoot it, only attacks other.
One thing that strikes me is, that when the zombie has killed a monster, it won't return to the player to follow.
It just stand with the killed corps, and as long here are no enemies, it stays there.
How do I make it follow the player again after killing?
zomby_friend
 This Would Be My Approach
#1606 posted by ijed [200.73.66.2] on 2014/11/13 12:52:27
But it will probably require some messing about to get it to work. You could drop this in a repeating function you call in the run and stand frames.
if (self.enemy.health < 0)
{
self.movetarget = "";
};
Basically, if my enemy is dead then set my movetarget (walk destination) to null, which will mean the first entity in the list - the player.
Won't follow other players in coop.
 OK
#1607 posted by madfox [84.26.177.181] on 2014/11/14 01:33:38
Out of the blue to ask this perculiar thing without explaining the changed qc.
In ai.qc in Found_Target I placed this part:
/*
Zomby_friend starts fight
*/
// ------------------------------------------------
float() FindMonster =
// ------------------------------------------------
{
local entity beast;
if (self.attack_state != ESCORTING)
return FALSE;
if (self.enemy)
return FALSE;
beast = findradius(self.origin, 1500);
while(beast)
{
if ( (beast.flags & FL_MONSTER) && visible(beast) && beast != self && beast.health > 0)
self.enemy = beast;
beast = beast.chain;
}
if (!self.enemy)
return FALSE;
FoundTarget();
return TRUE;
};
So I think it's the best place, now only puzzling.
 Big Ol' Parms Post
#1608 posted by Preach [77.98.165.95] on 2014/12/28 02:32:08
Been a while since I've had a chance to write something up to completion, here's a write-up on the parms mechanism, after the posts in the Mapping Help thread on that topic.
http://tomeofpreach.wordpress.com/2014/12/28/sending-values-between-levels/
To necros: I think that since the article manages to compress the player data into 3 parms values, it should be feasible to use cvars to smuggle that info - scratch1-3 would be enough. So as long as you accept you aren't getting anything like half-life's transition zones that can take other entities with them, a hub system should be feasible.
I guess the other practical things are to use some of the space in the third parameter as an index to select which spawn point the player should transfer to, and working out exactly how to send the command. Probably the best way would be as a single semicolon separated string, setting the scratch variables, then a "map" command in case we haven't visited this map yet, then the "load" command to attempt to load the save game for the map in progress. Probably overlooking something but it sounds solid enough...
#1609 posted by necros [99.227.110.3] on 2014/12/28 04:13:39
oh wow, that's crazy... you are a mad genius. :)
the savegame as hub system does have some other flaws though, for example, say a fiend leaps at you as you go through a hub save/load transition. when you return to the map, that fiend will still be floating in mid air to hit you. :(
I suppose you could designate transition zones as off limits so any monster in the zone when the a hub savegame is loaded would be move away or something.
ehhh, maybe it's better to use that scripting extension that lets you read/write to text files...
 Texting
#1610 posted by Kinn [86.164.147.200] on 2014/12/28 11:20:27
that scripting extension that lets you read/write to text files...
whoa - what's this and what engines support it?
 Oh Also
#1611 posted by Kinn [86.164.147.200] on 2014/12/28 11:32:28
Preach that is an excellent post.
 Exclusion Zone
#1612 posted by Preach [77.98.165.95] on 2014/12/28 13:51:23
I think once you accept that the monsters aren't gonna transition with you through a loading zone, you'd have to start with a recommendation to mappers that loading zones be designed to be isolated, free of items and largely inaccessible to monsters. You could enforce this somewhat on the mod side using code that runs with save game detection. When you notice that the player just loaded a saved game, findradius all the monsters near the player, and reset them back to their spawn location, optionally non-alert too.
That might be a neat idea to do with some of the further away monsters too, perhaps just the ones with patrol routes so that there's a limit to how much a sneaky player can exploit it. That would make it a bit more like Metal Gear Solid style zone transitions, which I think is a better model to have in mind than the Half-Life level continuity which is too hard to achieve. Mimicking the fade-to-black cutscene entering the loading zone and fade up on the other side would mask some of these "defensive moves"...
#1613 posted by necros [99.227.110.3] on 2014/12/28 18:54:35
http://quakewiki.org/wiki/FRIK_FILE
i don't know much about it, but i think it was used in that top-down RPG mod... which I am blanking on the name right now.
 Prydon Gate?
#1614 posted by Kinn [86.164.147.200] on 2014/12/28 19:41:35
well googling "frik file" gives me almost no more information other than that page you linked, and that Darkplaces supports it, so I'm guessing it's probably something that was supported in that one engine?
#1615 posted by necros [99.227.110.3] on 2014/12/28 19:53:06
well, yeah, in theory, any engine that supports the FRIK_FILE extension, but afaik, it's just DP.
it is a powerful system though, you could, in theory, transfer player info with a text file between savegame loading as well as use it to transfer over monsters in the trigger zone so that it behaved like half life. (although you might run into trouble if you brought over monsters that were not precached in the map originally).
 Transferring Monsters
#1616 posted by Preach [77.98.165.95] on 2014/12/29 21:31:47
You might have to work really hard to get monsters which weren't present before loaded in the level, but I think it might be possible. The thing you have going for you is that you can notice early enough that you need to run extra precaches, as the transfer data is available on the initial frame.
The thing you have to contend with is the modelindex field in the saved game you're loading (assuming the player has already visited the level) - if you precache extra models you'll probably invalidate the existing modelindex values, especially since you'd likely have to do all of this extra precaching during worldspawn. Given the choice we would prefer to do all the precaches after the other spawn-functions, where they couldn't wreck things.
So what we'd have to do is lots of clean-up when we get our onload function running. We could start with the idea that we need to do setmodel(self, self.model) on all the entities at this stage, and then try and work out all the exceptions we need to flag. Should be possible to get that working on anything that isn't a modelindex entity hack, and you know, you can't always save that kind of thing in a mod.
I did get excited for a little bit when I thought about how much storage you'd need for a monster, and figured I could get it down to 34 bits a monster. For a second I was excited as the parms provide enough space for 9 such monsters plus a player! Then I remembered we didn't have the parms and was saddened...
 Quick Question
#1617 posted by erc [78.172.189.129] on 2015/01/03 22:21:06
Is it possible to remove (or at least, hide) the "Saving to..." line that appears as a console message on top left of the screen which displays the full path to .sav file, by modifying the progs file? Lately I noticed that longish message distracts me greatly.
 Not Really
#1618 posted by Preach [77.98.165.95] on 2015/01/04 01:24:23
It's something that the engine does so in general you can't modify it away from the progs. If you had game saves which were being triggered from inside the progs (like an autosave feature or a hub system thing) you could mask it by appending ";echo \n\n\n\n" to the command string, but it's a bit hacky, you're wiping the whole notification area like that and making a bit of a mess of the console log.
If you wanted to adapt your favourite engine to not do it then it's a pretty easy change. Grab the source code for the engine, open host_cmd.c and comment out the following line:
Con_Printf ("Saving game to %s...\n", name);
#1619 posted by Spirit [92.196.13.174] on 2015/01/04 10:13:44
Bind your save key to "con_notifylines 0; save quick.sav; con_notifylines 4"
 Not Worthy! *takes Hat Off And Bows At Preach*
#1620 posted by Qmaster [50.45.36.210] on 2015/03/10 05:07:52
Like anyone can grab the source code for an engine, pop it into an IDE and hit compile and not get a gajillion errors.
fteqccgui.exe = easy QuakeC
<insert typical IDE here> = ERRORS!! The C++ Lord laughs at you and says "You're not supposed to be here!"
 @Spirit
#1621 posted by Baker [65.60.224.195] on 2015/03/10 08:14:11
That only works in JoeQuake-like engines.
I don't think Quakespasm supports it nor FitzQuake. DarkPlaces uses "con_notify".
#1622 posted by Spike [165.120.199.174] on 2015/03/10 09:33:36
@qmaster
that's more of a dependancy thingm combined with thesystem header files cahanging significantly with every single new ide version (especially between vendors).
qc just has NO dependancies - just compiler and vm. many qc mods still break to engine incompatabilities or compiler bugs. :P
@spirit
con_notifytime 0
set it back to 3 after 3 seconds have elapsed, or increase it over time.
there's a more portable solution for you. :)
#1623 posted by Baker [65.60.224.195] on 2015/03/10 23:35:23
The con_notifytime 0 does appear for a split second. Probably 1 frame.
(Which is why the non-standard con_notifylines 0 is nice)
 Thinking Fast
#1624 posted by Preach [62.30.150.129] on 2015/03/29 00:38:36
Somewhere on func_ recently there was discussion on 20fps animation in Quake, and one of the obstacles was that the QC might cope badly with them if the engine dropped below that framerate. Here in partial answer to that problem is a blog post:
https://tomeofpreach.wordpress.com/2015/03/28/thinking-fast/
It's also me trying to rewrite a much older post I made on func_ trying to describe exactly how the Quake engine deals with time and think functions. I hope the new approach taken makes it a bit easier to understand.
 QuakeWorld
#1625 posted by Spike [86.191.129.12] on 2015/03/29 03:49:55
aka sv_gameplayfix_multiplethinks (exists as a cvar in both fte+dp)
vanilla quakeworld already performs multiple thinks per second if the real framerate drops too low somehow.
it'll just keep running think functions until it catches up with the actual time.
(yes, this means that really low think intervals is just wasteful).
#1626 posted by necros [99.227.108.31] on 2015/03/29 04:48:27
how does it behave if you set nextthink = 1?
#1627 posted by Spike [86.191.129.12] on 2015/03/29 06:55:17
gives up because it didn't progress at all.
there's a lot of mods that use self.nextthink = time;
the time global will presumably stick one frame behind.
its probably also worth mentioning that quakeworld really doesn't do the whole fixed interval thing at all, favouring latency over smoothness (vanilla doesn't support interpolation at all).
it doesn't exactly do the order thing either, if you abuse newmis
#1628 posted by necros [99.227.108.31] on 2015/03/29 15:28:30
gives up because it didn't progress at all.
does it think exactly once though? otherwise, it is another compatibility break with winquake. :(
i use nextthink = 1 when I need one single think update on the very next frame.
#1629 posted by Spike [86.191.129.12] on 2015/03/29 18:53:12
@necros
vanilla quakeworld: that's an infinite loop
fte: exactly what you want: exactly one think per physics frame if you set nextthink <= time like that.
@Preach
'If the drop to 10fps was only temporary then the entity may “catch up” once the framerate increases, but this will result in strange extra-fast behaviour in the meantime'
This is incorrect. time will be clamped to the start of the frame, even in vanilla nq.
This means that while an entity may run slowly in nq, it will NOT catch up / run fast once framerates increase.
(the nextthink = 1 example should give the time value that was correct at the start of the frame in every engine, due to this clamping - it will still be meaningful for the thinks of other entities although it'll happen about half a frame sooner than it otherwise would).
 Thanks Spike
#1630 posted by Preach [62.30.150.129] on 2015/03/30 00:04:46
I've updated the article, although now I'm a bit worried that I have the way frametime increases the wrong way round. From double-checking the source (what I should have done rather than writing the article from memory!) it looks like thinks are actually triggered when they're less than the true time plus the next frame length. This means the startframe function has the true time, but it's actually earlier than all the times thinks will occur this frame. The engine still lies about what time it is - but lies that it's the future rather than the past.
When it's morning and I'm less prone to making a mistake I'll put a second amendment in the article and fix all the tables
#1631 posted by Spike [86.191.129.12] on 2015/03/30 01:46:13
depends how you define it.
startframe gets the time at the start of the frame. once the frame is done, time is updated to starttime + frametime. ie: the physics frame covers a block of time rather than a single absolute timestamp. Its still lying about being in the past (time should be starttime+frametime), but logically it somewhat IS in the past, as its trying to update those entities that still have thinks pending since the last frame.
 Truth, Justice And All That
#1632 posted by Preach [62.30.150.129] on 2015/03/30 09:36:59
Yeah, the problem is that the article is taking the position that any function not told that time = starttime + frametime is being lied to (and if you're lied to, you can't successfully simulate multiple thinks). Under that definition, the startframe function is also lied to, since it is told time = starttime. However, it can always reason about which think functions should run this frame from this position, so I think it would be better to redefine what's lying etc...
#1633 posted by Spike [86.191.129.12] on 2015/03/30 17:23:44
'but lies that it's the future rather than the past'
startframe is told its in the past, not the future.
think times are unordered, but always within the time period defined by the frame.
if you want to update the entities to the _current_ time then you should be using while(ent.nextthink<=time+frametime)
just make sure you don't do this on movetype_push entities.
 Projectiles
#1634 posted by madfox [84.84.178.104] on 2015/04/29 23:12:44
I'm trying to obtain a kind of a flamethrower for a model.
I'm a bad coder, everything just happens on the experience of addding to an excisting code.
To get the explod2.spr working I made a flame script that looks like this:
$frame 0 1 2 3 4 5 6 7 8 9 10 11
void() flam_stand1 =[ 0, flam_stand2 ] {};
void() flam_stand2 =[ 1, flam_stand3 ] {};
void() flam_stand3 =[ 2, flam_stand4 ] {};
void() flam_stand4 =[ 3, flam_stand5 ] {};
void() flam_stand5 =[ 4, flam_stand6 ] {};
void() flam_stand6 =[ 5, flam_stand7 ] {};
void() flam_stand7 =[ 6, flam_stand8 ] {};
void() flam_stand8 =[ 7, flam_stand9 ] {};
void() flam_stand9 =[ 8, flam_stand10 ] {};
void() flam_stand10 =[ 9, flam_stand11 ] {};
void() flam_stand11 =[ 10, flam_stand12 ] {};
void() flam_stand12 =[ 11, flam_stand13 ] {};
void() flam_stand13 =[ 12, flam_stand1 ] {};
void() model_flam =
{
precache_model ("progs/explod2.spr");
precache_sound ("ambience/waterfal.wav");
ambientsound (self.origin, "ambience/waterfal.wav", 0.5, ATTN_NORM);
self.solid = SOLID_BBOX;
self.movetype = MOVETYPE_NONE;
setmodel (self, "progs/explod2.spr");
setsize (self, '16 16 16', '24 24 24');
self.think = flam_stand1;
self.nextthink = time + 0.1;
};
void() FlameExplode =
{
// T_RadiusDamage (self, self.owner, 120, world);
// WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
// WriteByte (MSG_BROADCAST, TE_EXPLOSION);
// WriteCoord (MSG_BROADCAST, self.origin_x);
// WriteCoord (MSG_BROADCAST, self.origin_y);
// WriteCoord (MSG_BROADCAST, self.origin_z);
// BecomeFExplosion ();
T_RadiusDamage (self, self.owner, 40, world);
sound (self, CHAN_VOICE, "weapons/r_exp3.wav", 1, ATTN_NORM);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
self.velocity = '0 0 0';
self.touch = SUB_Null;
setmodel (self, "progs/explod2.spr");
self.solid = SOLID_NOT;
s_explode1 ();
};
void() FlameTouch =
{
if (other == self.owner)
return; // don't explode on owner
if (other.takedamage == DAMAGE_AIM)
{
FlameExplode();
return;
}
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
/*
================
W_FireFlame
================
*/
void() W_FireFlame =
{
local entity missile;
self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
missile.classname = "flame";
// set missile speed
makevectors (self.v_angle);
if (self.v_angle_x)
missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
else
{
missile.velocity = aim(self, 10000);
missile.velocity = missile.velocity * 600;
missile.velocity_z = 200;
}
missile.avelocity = '300 300 300';
missile.angles = vectoangles(missile.velocity);
missile.touch = FlameTouch;
// set missile duration
missile.nextthink = time + 2.5;
missile.think = FlameExplode;
setmodel (missile, "progs/explod2.spr");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin);
};
I compared the sprite with the grenade code of the ogre.
If I can stop it tumbling and make a straight foreward replacement of the sprite
it could give an idea of a flame thrower.
The result of this is, that the sprite only gives one frame, and all projectiles head east.
What should I do to prevent this?
 Madfox
#1635 posted by Preach [62.30.150.129] on 2015/04/30 06:38:44
You aren't running the model_flam function anywhere, which partly explains why you aren't getting an animation.
 Can't Flim-flam
#1636 posted by onetruepurple [5.172.252.131] on 2015/04/30 09:02:51
the model_flam.
 Rascalling Again
#1637 posted by madfox [84.84.178.104] on 2015/04/30 11:24:17
I'm just shooting in the dark.
I tried another way in the entity.qc by making a missile_explode, _touch, _launch and make the entity shoot the sprite. I only see one sprite frame, while there are 12.
Trying to add the flameframes of the sprite I can't use the entity.qc because it has it own frames.
The weapon.qc has already the grenade sprite so there it won't fit either.
So the script was a site file to make the entity launch the sprite as an attack scene of a kind of flamethrower.
Where do I make this call to the flame.mdl.
Probably it needs another statement to get the result.
 Spagetti
#1638 posted by madfox [84.84.178.104] on 2015/04/30 11:29:02
What I did was the first part at the end of model_flam make a flame.qc
and try to use the rest as the attack scene for the entity.
 Why Not
#1639 posted by ijed [200.73.66.2] on 2015/04/30 17:04:52
Steal the one from the Rubicon2 source?
 Not Bad
#1640 posted by madfox [84.84.178.104] on 2015/05/01 01:24:39
reminds me of all the maps I haven't played yet.
 Increasing The Character Count Of My Trigger_multiple Messages
#1641 posted by Darth_Stewie [79.65.200.86] on 2015/07/01 01:31:11
How do I do this? Do I have to edit something in the triggers.qc or suchplace? Any guidance would be most highly appreciated.
#1642 posted by necros [174.113.85.164] on 2015/07/01 03:33:49
that is limited by the engine, unfortunately. :(
be more succint, or use trigger_multiple that hits 2 trigger_relays, one with no delay, another with a delay of 2 seconds.
some custom engines can display more text, I think?
 Not An Actual Question But
#1643 posted by Daya [90.58.150.150] on 2015/07/11 16:49:17
The Inside3D website has been hacked for a while (and somehow nobody on the forum mentionned this) and that really bums me out because its tutorial page had a lot of useful stuff that helped me started some coding.
Is there a way to get them back, or at least some of them?
#1644 posted by Spirit [80.187.106.56] on 2015/07/11 17:45:31
Archive.org
 Probably Asked, But...
#1645 posted by adib [186.228.0.26] on 2015/07/16 22:35:32
... where's that sticky post pointing the very basics to qc newbies?
I was thinking about another "total conversion": new monsters, new weapons, new player. How much the engine code is coupled to Quake stock assets? If I replace the Shambler model for a Santa Claus that shoots cotton candy, will I break something?
#1646 posted by adib [186.228.0.26] on 2015/07/16 22:40:09
I think the right question is: in order to do a total conversion, what can I actually replace without touching engine code?
 Everything
#1647 posted by onetruepurple [93.105.176.60] on 2015/07/16 22:43:09
 Separation Anxiety
#1648 posted by Preach [77.99.55.146] on 2015/07/17 01:02:18
Quake actually has a really good segregation of duties between the engine and the QC code - I've heard how much harder it is to decouple gameplay and visual modifications in DooM. A good example to have in mind is the total conversion Malice, which replaced every graphical and audio asset in Quake, with completely different enemy behaviour and gameplay. All of this was accomplished without any modification of the engine (it predates the source being published).
There are some places where changes are more difficult/impossible to make, like the HUD or the fundamental physics or the rendering of surfaces. But if you want a monster with all new animations, behaviours and attacks, that's easily in reach of QC.
It's a shame Inside3d has been hacked, as that used to be a good place to start. However, the best resource for a new coder who wants to modify monsters is AI Cafe, and although the original site is long gone there's a mirror at:
http://www.quakewiki.net/archives/aicafe/tutorial/main.htm
Although I love promoting my own site, unfortunately it's pitched at the vanishingly small "experienced QC" crowd, so go do the AI Cafe tutorials first.
#1649 posted by scar3crow [68.35.22.60] on 2015/07/17 03:52:29
Funny you should mention that today... with AtomicGamer going down, Inside3d is in the process of relocating to insideqc.com FrikaC registered it today and already migrated the forums. Hopefully less... hacked at, this time.
 Subculture
#1650 posted by madfox [84.84.178.104] on 2015/07/30 23:10:03
While playing Criterion's "SubCulture" underwater adventure I found in the data bank a file called scen1.bsp.
I know it's a stupid question, but in my attempt to break it open, hoping to make my own levels, is a bit top off my hat.
Sureley it's a complete diferent bsp file as the regular quake maps, but I feel I'm not the first one to try.
Is there any chance of luck making this happen, or is it the same dead end as trying to decompile the Malice progs?
 I LOVE THAT GAME
#1651 posted by Spirit [92.196.111.172] on 2015/07/30 23:43:57
It has nothing to do with Quake's bsp format, it uses an early version of Renderware. I once managed to persuade Rich to reverse engineer the format of the models, so Noesis supports those. But I think not the map itself, always wanted to try that.
 Anchor
#1652 posted by madfox [84.84.178.104] on 2015/08/01 09:56:57
I had my old 3dxf vodoo card,
and saw there was a retexturing project in 2008.
Games like Unreal and Rune have a fine look with it.
So I'm not the only tin can in the ocean, but I sure would like to make
maps for it. It would make the game's potential so much larger.
 Hi Warren!
#1653 posted by Shambler [92.22.73.141] on 2015/08/22 20:23:44
#1654 posted by JneeraZ [12.252.11.134] on 2015/08/22 20:29:37
WTF? Couldn't find it.
Anyway ... thanks!
My question for those who are in the know is this ... in the monster death routines, does it add any efficiency to change this:
void() wiz_death8 =[ $death8, wiz_death8 ] {};
Into this:
void() wiz_death8 =[ $death8, SUB_Null ] {};
It seems like in the original code it will just loop forever on the corpse setting the last death frame for all time.
Why is SUB_Null a terrible idea?
#1655 posted by necros [109.201.154.191] on 2015/08/22 21:28:03
you are correct, it does loop forever.
doing sub_null is a good idea and I don't know why ID chose not to do that. it's possible that at the time they were doing the scripts that entities had to be 'active' with a nextthink and valid think to be able to move (this is how bsp movers work, for example).
what i prefer doing is to make an ai_dead() method that i run at the end of any monsters death anim. this way I can hook things in easily to all monsters and in this method, i'd just do a self.think = SUB_NULL; along with a self.nextthink = 0.
if you really want to be nuts, doing self.nextthink = 0 is probably the most efficient because that will cause it to never think with a single operation. but that's just getting silly. ;) ;)
 Deez Nuts!
#1656 posted by SleepwalkR [93.209.76.92] on 2015/08/22 21:34:42
Got eeeem!
#1657 posted by JneeraZ [12.252.11.134] on 2015/08/23 21:44:01
So, here we are again ... Is there any way to use the "cvar_set" function without it spamming to the screen?
For example:
cvar_set ("sv_gravity", ftos(self.count));
Works great but it spams the fact that's changing it to the screen...
#1658 posted by necros [109.201.154.199] on 2015/08/23 21:50:27
is using stuffcmd an option?
#1659 posted by JneeraZ [12.252.11.134] on 2015/08/23 22:00:31
Good idea, but it spams the results too.
I mean, it's not terrible but it's less clean looking ...
 ???
#1660 posted by mfx [77.179.172.128] on 2015/08/23 22:04:13
/n /n /n
/n
/n
#1661 posted by mfx [77.179.172.128] on 2015/08/23 22:05:39
/not
#1662 posted by necros [109.201.154.199] on 2015/08/23 22:45:26
it does? i have used stuffcmd a lot, i honestly don't remember it doing that. :(
#1663 posted by JneeraZ [12.252.11.134] on 2015/08/23 23:01:45
Maybe changing the gravity is a special case ... it actually lies too. It says gravity has been set to the older value instead of the current one. It's a major troll.
#1664 posted by JneeraZ [12.252.11.134] on 2015/08/23 23:01:57
stuffcmd ( player, "sv_gravity " );
stuffcmd ( player, ftos(self.count) );
stuffcmd ( player, "\n" );
 Technical Tip
#1665 posted by Preach [77.99.55.146] on 2015/08/23 23:16:17
You should use servercmd instead of stuffcmd, because in coop the player may not have the rights to change server settings. Not sure if it spams the console less...
#1666 posted by JneeraZ [12.252.11.134] on 2015/08/23 23:55:59
My QuakeC has never heard of servercmd or server_cmd ... ?? Google is coming up pretty dry as well.
#1667 posted by necros [109.201.154.199] on 2015/08/24 00:04:42
i think he meant localcmd. executes commands as if they were typed on the server's console. (stuffcmd is like if the player types it)
 Oh Cool
#1668 posted by necros [109.201.154.199] on 2015/08/24 00:06:54
http://www.gamers.org/dEngine/quake/spec/quake-spec34/qc-menu.htm
is useful. i remember printing this out way back... lots of nice info in there and easy to sort through. see 8.10 for localcmd.
#1669 posted by JneeraZ [12.252.11.134] on 2015/08/24 00:33:06
Thanks for trying but, no, same ...
#1670 posted by JneeraZ [12.252.11.134] on 2015/08/24 00:33:32
Might be that changing gravity is just one of those things that Quake feels the need to tell everyone about. :)
#1671 posted by necros [109.201.154.199] on 2015/08/24 00:39:38
ohh bizarre, i just noticed that. i think that is the only (or one of the very few?) variables that, when changed, prints text to the console.
whelp, you can try mfx's suggestion of just adding 3 extra '/n's to push that output away, but they'd have to be on the NEXT frame, so you couldn't just do localcmd("sv_gravity 100\n\n\n\n\n");
you'd need to track when you changed the gravity, and then next frame run the newlines on stuffcmd for EACH client. ugh.....
#1672 posted by JneeraZ [12.252.11.134] on 2015/08/24 00:45:25
I tried setting it up so it would think 0.1 seconds later, jam 3 newlines in but it seems to ignore those for whatever reason. Nothing happens.
Unless there's an elegant solution, I'll just live with it. Chalk it up to Quake being Quake...
#1673 posted by metlslime [107.77.92.93] on 2015/08/24 00:50:10
Try setting .gravity on every entity individually?
#1674 posted by metlslime [107.77.92.93] on 2015/08/24 00:50:33
How does quake do it for e1m8?
#1675 posted by JneeraZ [12.252.11.134] on 2015/08/24 01:08:44
E1M8 is a QuakeC hack ...
cvar_set ("sv_gravity", "100");
I guess they don't care that it spams the message out. Or maybe you just don't notice it during the level load, I dunno ...
It's right at the very top of "void() worldspawn" ...
#1676 posted by necros [109.201.154.199] on 2015/08/24 01:29:18
yeah, i think at the time that command is run, the player isn't spawned in yet, so they never receive the message.
try using metl's suggestion of setting .gravity while cycling through every entity in the map with find()... it's goofy, but it'd work quietly.
#1677 posted by Lunaran [24.180.199.42] on 2015/09/06 22:40:05
Some time recently, either in this thread or modeling help (I think), someone (probably preach) talked about ways to make an entity out of more than one alias model, and have them move in sync via quakec trickery.
It's not a hard problem at all - unless the entity is an AI being moved around by the navigation code. then movetogoal might not succeed for all parts of the collective entity because some of it will collide with something and the rest won't, and you'll get a discontinuity. Constant setorigin()s are laborious and not fully reliable, especially in the above case, and polling/setting velocity will lead to weird one-think lags after direction changes. Maintaining yaw is just as bad.
It might actually have been some CSQC or FTEQW extension? Nobody documents anything over there so it's impossible to just look it up.
My parameters are that I'm okay with one entity being the collision master and all the rest being nonsolid, but if the 'master' is still being driven by ai_forward()s and all that the 'slave' has to react accordingly.
#1678 posted by Lunaran [24.180.199.42] on 2015/09/06 23:17:25
A better way to ask (with some forethought put into it):
movetogoal() in quakeC is called during the think cycle, but it's evaluated during physics/touching, correct? So if the master does an ai_forward(20) at an enemy 10 units away, physics will move it 10 units (until the boxes touch). If the slave is thinking in tandem (and it should be if it's also trying to match frames) then it will already have thunk by the time physics gets around to the master's SV_MoveToGoal(). It can't see that little bit into the future physics cycle to know how far its master is going to move. So, is it impossible? Or have I got this wrong?
#1679 posted by necros [109.201.152.16] on 2015/09/06 23:27:05
no, the 'physics' of the ai moves are done as they are called. this is how you can use walkmove and get a return value on if the walkmove was successful or not.
this means you can recursively or iteratively solve walkmoves in a single frame and you don't need to rely on child entities to think for themselves. you can have the master run all the thinking on its children so make sure everything is synchronized.
#1680 posted by necros [109.201.152.16] on 2015/09/07 00:05:41
btw: movetogoal does not return anything, but you can just check if the origin of the entity after you called the method is the same as before. if they are, then it failed...
#1681 posted by Lunaran [24.180.199.42] on 2015/09/07 00:35:47
How do movetogoal and walkmove interact with model lerping?
#1682 posted by necros [109.201.152.16] on 2015/09/07 02:08:23
only seems to matter where the monster is at the end of the frame, not matter on how many times any of those methods were called.
 Setorigin Stuff
#1683 posted by Preach [77.99.55.146] on 2015/09/07 02:37:31
If you do decide to go down the setorigin route, I recommend use the EndFrame function from
https://tomeofpreach.wordpress.com/2014/05/24/easily-fixing-the-endframe-function/
This ensures no QC which runs later in the frame can desync your models.
#1684 posted by Lunaran [24.180.199.42] on 2015/09/07 17:26:47
So my approach should be
- give each model the same origin for sanity's sake
- make sure the attachment thinks second, presumably by having the master itself spawn() the attachment so it's a higher numbered entity
- have the master be aware of how far it actually moved each think and notify its slave(s)
- maintain the same ideal_yaw and yawspeed on all parts
- do a final setorigin() in an end of frame function if necessary (wouldn't having the master setorigin() the slaves at the start of its own think have the same outcome?)
didn't ijed do something like this in RRP? with destroyable gun arms or something?
 Nope
#1685 posted by ijed [200.73.66.2] on 2015/09/07 17:38:04
Those were just more animation frames with the arms hidden inside the body and a value keeping track of the destruction state.
#1686 posted by ijed [200.73.66.2] on 2015/09/07 17:43:37
I've only used multiple entities for a single enemy when I wanted them to move independently - to help with navigation, provide effects of one type or another or not move locked to the master monster's origin.
FTEQCC allows you to have multiple meshes used by a single monster if needs be, removing that blocker.
What are you aiming for?
#1687 posted by Lunaran [24.180.199.42] on 2015/09/07 22:24:02
Mostly saving vert precision on the important core of a model without sacrificing any to its giant tentacles.
FTEQCC allows you to have multiple meshes used by a single monster if needs be
Yeah, how? It's not documented anywhere.
#1688 posted by Spike [86.180.170.55] on 2015/09/08 03:18:56
FTEQCC doesn't really provide anything that couldn't otherwise be achieved with perverse unreadable QC (like arrays).
the qcc really doesn't have anything to do with multiple meshes - anything along those lines are engine extensions rather than qcc ones.
in order for an entity's interpolation to match another, it should (depending on the client in question) update its origin at the same times, its movetype, its angles, its .frame, and its onground flag. If any of these differ at the end of a frame (this includes independant player physics partial frames) then a client may see a desync.
the client may also see a desync caused by packet overflows (or equivelent) also (although often that would just manifest as completely invisible ents).
MOVETYPE_FOLLOW(if the follower has a higher entity number which is fine if you manually spawn the second entity within the first entity's own spawn function), customizeentityforclient, setattachment, or csqc can all be used to easily keep a 'sub' entity tracking a parent. you could also give the follower a nextthink=time for a similar effect and limitation as movetype_follow. or you can use EndFrame (either the extension or preach's hack).
In QuakeWorld, other players are predicted. There is no way to guarentee that an entity can exactly follow a player other than with setattachment or csqc with quakeworld protocols (non-players are not affected by this limitation, and in fact vanilla qw has no non-player interpolation at all, but that's just vanilla being lame).
setattachment is the easiest and most reliable, but requires dp or fteqw in order to work (on the plus side, it can also work with md3/iqm tags - use an empty tagname for formats with no tags/bones and it'll attach to the entity itself). It was made for this sort of thing.
Note that the subentity's origin is typically set to '0 0 0', which can be a little weird.
 Well
#1689 posted by ijed [200.73.66.2] on 2015/09/08 16:34:00
To use multiple different meshes from the same creature, back in RMQ/Schism, I added this:
$framevalue 0
After each listing of animations as $frame for each model.
They still need precaching of course and setting to self.model = thenewone when you want to swap things about.
Here's the Ogre Qc from back then as reference:
http://pastebin.com/JiDMsbSL
 As To
#1690 posted by ijed [200.73.66.2] on 2015/09/08 16:38:56
The whys and wherefores, I bow to Spike's superior knowledge - and Gb who figured out how to use this back in the day.
If memory serves, it was that other compilers would explode when trying to parse the additional animations rather than spit out a usable progs.dat
 Bump Around
#1691 posted by Lunaran [24.180.199.42] on 2015/09/08 17:15:39
I'm forced to confront an issue I've noticed out of the corner of my eye a lot - monsters whose yaw angles will seem to spaz back and forth while meleeing, specifically on melee frames that use ai_charge().
ai_charge leads to SV_MoveToGoal() in sv_move.c, which eventually winds up calling SV_NewChaseDir() under certain conditions. SV_NewChaseDir() rounds ideal_yaw to the nearest 45, tries some navigation stuff, and if none of it is successful, overwrites the entity's ideal_yaw with the rounded value. I can't really tell why.
The outcome of this is that if a monster is in melee frames (when it's really close to the player) which call ai_charge() (which they nearly all do, since most monsters' melee attacks have some forward movement to keep the player close), every couple of frames its yaw is pulled hard to one side or the other, then immediately lerps back as the monster yaws back to its enemy. I've verified this is the case with shotgun bprint debugging, and I've verified it happens in id progs 1.06 too.
What can I do? I'd rather not disable a monster's ability to yaw by taking out the ai_charge()s. Can anyone who understands SV_MoveToGoal() better than I do suggest anything brilliant?
 Dull Idea
#1692 posted by ijed [200.73.66.2] on 2015/09/08 20:39:21
To me it seems that the original intention there is to just have the monster stay close, so why not stick with that.
The method of aiming the monster at the player and then pushing it forward makes it wobble, as you say, so why not add a new ai_propel(); which does it the opposite way round - move the monster along the shortest point between it and the player and then give it the ideal yaw.
Potentially this could make it move sideways if something weird happens but that's nothing you couldn't account for by testing the facing beforehand and discounting the propel if the yaw is too wacky - possibly reverting to good 'ol ai_charge(); if that's the case.
There are probably better, coder ideas to be had, but this could be an interesting thing to mess about with.
#1693 posted by Lunaran [24.180.199.42] on 2015/09/09 00:36:39
That doesn't solve the problem. c changes the yaw to something and the model renders and you see it twerk left or right for a few render frames, regardless of what order the qc moves and yaws before or after that happens.
 Lazy Idea
#1694 posted by Preach [77.99.55.146] on 2015/09/09 00:43:11
Adding
self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
straight after movetogoal (d); in ai_charge is certainly a straightforward way to eliminate the wobble. What you might ask is how much difference it makes elsewhere. I mean, we're overwriting the change SV_NewChaseDir makes, and while we've identified a case where it makes an irritating change, does it sometimes make a beneficial change instead? You might imagine that on occasions when it finds a direction the monster can walk in, we may want to retain that information.
I'd argue that no, almost every time it makes no difference besides the visual glitch. My reason is that the preceding line in ai_charge is ai_face ();. This actually resets ideal_yaw in the same way our added line of code does (I straight copy-pasted it from ai_face). So any time an ai_charge is followed by another ai_charge next frame*, the information from SV_NewChaseDir is discarded without being used. Keeping it will make little to no difference.
Ah, if only they could all be one-liners...
*Here by "next frame" I mean next monster animation frame, not engine frame.
 Duh
#1695 posted by Lunaran [24.180.199.42] on 2015/09/09 02:00:41
I guess that's kind of what ijed was getting at too. Just reset it immediately. i'm tired. :p
Will test soon.
#1696 posted by necros [173.199.65.21] on 2015/09/09 03:18:59
...or use walkmove? i never use the ai_charge method for exactly the reason you stated.
#1697 posted by Lunaran [24.180.199.42] on 2015/09/09 04:25:57
the ijed/preach method actually makes it WORSE. the monster spins like a ballerina.
the necros method works like a charm. walkmove is all or nothing, though, so this
if ( !walkmove(self.ideal_yaw, d) )
walkmove(self.ideal_yaw, d * 0.5);
serves as a good functional compromise.
ai_charge_side uses walkmove, and now that I understand all this I really don't know why ai_charge didn't already.
Thanks, guys!
#1698 posted by necros [173.199.65.21] on 2015/09/09 05:44:40
do
{
····if (!walkmove_builtin(yaw, stepDist))
········stepDist = stepDist * 0.5;
····else
········stepCounter = stepCounter + stepDist;
} while (stepCounter < step && stepDist > 1 && stepDist < (step - stepCounter));
Preach clued me in on this gem. This will always walk as much as possible but due to some mathyness, will only every iterate a maximum of 6(?) times.
#1699 posted by necros [173.199.65.21] on 2015/09/09 05:46:39
actually, come to think of it, i wrapped movetogoal in a method that essentially replaced movetogoal with walkmove. call movetogoal with distance of 1, reset position back to where it was before but record the direction it moved in, then use walkmove to do the actual move with the proper distance.
this solves the problem with monsters not willingly walking inside other bboxes, even if they are non-solid (and thereby not generating touch events).
 Piroette
#1700 posted by Preach [77.99.55.146] on 2015/09/09 18:59:06
I can't understand how your monster spins so much after the change I suggested, certainly when I played around with the ogre it didn't cause such a difference. I will admit that it doesn't fix the issue - in my testing I wasn't reliably replicating the glitch. Luring the ogre to a wall on a corner makes it occur regularly, both with and without the change.
However, I think I may understand better why it's happening. I don't think it's due to the failure mode of SV_NewChaseDir you spotted, because that only changes ideal_yaw, and ideal_yaw is reset before the monster is turned towards it next (barring any functions above ai_charge calling ChangeYaw).
Instead, what if all the functions are behaving correctly in isolation, but the result is strange. Imagine that the monster is essentially trapped near the player, and movetogoal succeeds in moving the monster only occasionally. On those occasions, it's likely to move the monster away from the obstructing player. Then next frame there is space for the the monster to move in the correct direction and it returns to where it was. The net result is that the monster shuffled sideways for one frame.
But tragically, this actually could cause the one frame jump in angles! The reason is that ai_face calculates the angle for the monster to face based on the relative origins of the pair. So a one frame shift in origin has a corresponding one frame shift in facing. It might be a little hard to reliably establish this is how it works though.
Replacing movetogoal with walkmove would certainly eliminate this issue, as the monster would only ever succeed in changing origin if they had moved straight towards the player, but it does mean that you're losing the ability for a monster to slip round a barely obstructing obstacle while charging. It's not about how far the monster is moving (both functions are all or nothing), it's about which directions they try.
If this is the right explanation of the glitch, then I think it boils down to: monster angle changes should result from the player moving round the monster, but not from the monster moving round the player (because the latter tends to be back and forth and glitchy). So something like:
self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
movetogoal (d); // done in C code...
if(approx_equal(vectoyaw(self.enemy.origin - self.origin), self.ideal_yaw))
ai_face ();
Prior to movetogoal, you only change the direction you'd like to walk , not your actual angles. Then after you move, you check to see if the angle is still more or less the same. If you moved straight towards the player or not at all, then it will be (in the former case I suspect it may vary slightly so this comparison should be approximate). If you shuffled sideways then it differs, and this frame you refuse to change angles.
#1701 posted by necros [66.102.6.224] on 2015/09/09 22:45:06
but it does mean that you're losing the ability for a monster to slip round a barely obstructing obstacle while charging
That will rarely happen anyway though since it would need several consecutive frames for it to successfully walk around even the smallest of obstacles.
#1702 posted by necros [173.199.65.41] on 2015/09/10 01:20:09
oh come to think of it, i think i understand what you mean; if you have a monster charging at you and it hits an angled wall or railing or something, it can still walk towards you following the railing whereas walkmove would just stop dead.
#1703 posted by Lunaran [24.180.199.42] on 2015/09/16 02:58:49
String concatenation without crazy hacked compilers: possible? I can do it by abusing the 'stuffcmd' buffer and changing the player's name, waiting a frame, getting the player's .netname and then stuffcmding it back, but this prints messages about the player's name changing.
 String Concat
#1704 posted by Spike [86.191.130.102] on 2015/09/16 03:21:20
depends what you're cating. part of the problem is that even if you can hack the player's netname like that, you have to do it for every single string.
one trick (abused quite effectively in prydon gate, also in frikbot to a lesser extent) is to use writebytes for your sprints and centerprints and stuff. this can generally get close enough without visible side effects, but does mean that your strings need to be hard coded to some extent.
the last part of your message can still use writestring, so at least that part of it doesn't need to be hardcoded.
quakeworld could do something with the server's localinfo, but this does still impose a frame's delay due to localcmd.
#1705 posted by Lunaran [24.180.199.42] on 2015/09/16 04:35:11
Yeah, I'm trying to create guaranteed unique targetnames, so centerprint effectively goes into the void.
Fuck it, I might as well just make them all numbers.
Here's a real contribution: I made a Notepad++ userDefineLang.xml preset for QuakeC syntax highlighting.
http://pastebin.com/G0s8mw92
it also colors quake's required globals (like self etc) and all the builtins.
 Well, That Doesn't Work
#1706 posted by Lunaran [24.180.199.42] on 2015/09/16 05:23:28
apparently if you set something's targetname to just ftos(some_integer), it somehow changes to other numbers as you move around!
#1707 posted by necros [173.199.65.21] on 2015/09/16 05:36:07
ftos stores the string it creates in a shared spot in memory. if you call ftos multiple times in a frame, all strings you assigned ftos to, even if they were different numbers, will have the number of the last ftos call.
this is true for vtos as well.
 Ftos
#1708 posted by Spike [86.191.130.102] on 2015/09/16 05:46:30
works in fte. :)
but yeah, in most engines, builtins that return temporary strings will overwrite the previously returned one(s), such that the old reference now refers to the new value. which is really useless.
either that or it starts complaining about stale/invalid tempstrings. including when saving games. potentially even with crash-to-console results...
as a general rule, if you have a tempstring, NEVER store it to a field or global (if you have the somewhat common frik_file engine extension, then you can use strzone for these usecases).
findfloat doesn't exist in vanilla qc (and hacking find to find a float is unreliable too, and potentially crashy), but you can use nextent to itterate over all entities manually. obviously its less efficient, but if you're really trying to avoid extensions then you won't have more than 600 ents anyway.
 Ok I'm Going To Bed
#1709 posted by Lunaran [24.180.199.42] on 2015/09/16 06:15:02
I spawn an entity, set its targetname to self.netname, check it with an eprint, change my name, eprint it again, and the fucking targetname on the entity has changed to my new name.
I don't have a fucking clue in the world what's going on here.
#1710 posted by Lunaran [24.180.199.42] on 2015/09/16 06:17:33
wait, are ALL these string fields referenced rather than copied?
 Styring References
#1711 posted by Preach [77.99.55.146] on 2015/09/16 08:08:47
Lunaran: yes, it's a reference to your name string buffer. Some engines offer extensions like "zone" for allocating new buffers.
Depending on what you need to do with strings, there may be a way to do it building the string character by character at time of use. This is the way that Prydon Gate makes its menus, for example. I wrote some articles on how to organise this so it's not quite as awful as it sounds, starting at https://tomeofpreach.wordpress.com/2013/03/28/text-manipulation-in-quake-i-the-basics/
#1712 posted by Lunaran [24.180.199.42] on 2015/09/16 14:51:35
I read those. Doesn't work for my needs, unfortunately. Seems any mechanism I use to exploit that buffer trick is going to be foiled by whatever field I try to exploit to capture its result. I don't want to start exploring engine specific code, either.
A giant lookup table it is then.
 Lunaran
#1713 posted by mfx [78.48.219.28] on 2015/09/16 20:26:38
Thx for the xml!
 Lookup Tables
#1714 posted by Preach [77.99.55.146] on 2015/09/16 20:47:40
What you up to Lunaran? Sometimes there are ways to avoid them in QC, as they're never a pleasant task to maintain.
#1715 posted by necros [66.102.6.228] on 2015/09/16 22:47:21
I assumed a giant array of strings each with a unique name?
 Yep
#1716 posted by Lunaran [24.180.199.42] on 2015/09/17 06:52:35
f.write("\\tswitch(num)\\n\\t{\\n")
for i in xrange(256):
. s = str(i)
. f.write("\\t\\tcase "+s+": return "node"+s+"";\\n")
f.write("\\t}\\n\\treturn string_null;\\n}\\n\\n")
#1717 posted by Lunaran [24.180.199.42] on 2015/09/17 06:53:00
hm. func is weird with backslashes.
 QC Math To Calc Odd / Even Number
#1718 posted by Teknoskillz [50.136.116.163] on 2015/09/25 18:38:38
Has anyone run across or can post some QC that can tell weather or not a number on the positive number line is odd or even?
#1719 posted by Mandel [80.217.22.116] on 2015/09/25 19:56:27
Surely, lacking a modulo operator, something like this must work:
if (number & 0x1) {
// odd
}
else {
// even
}
#1720 posted by Lunaran [24.180.199.42] on 2015/09/25 22:46:35
"positive number line"
#1721 posted by Spike [86.176.35.74] on 2015/09/25 23:22:05
float(float a, float n) modf = {
return a - (n * floor(a/n));
};
modulo with floating point types is fun.
but yeah, if its just odd vs even, just use value&1.
 Weapon Animation Going Faster Than 10 Fps
#1722 posted by Daya [86.192.38.52] on 2015/09/30 11:21:13
For some who've been on the modelling help thread, I've been working on a machinegun weapon. I've been able to complete them and are ready to be implemented in the game.
Thing is, the viewmodel has been designed to run at 0.05 sec for each frame, more than the minimum 0.1 sec. But I've seen there's a way to go past this, as seen here: https://youtu.be/E5zyhlZ1xVI?t=2m22s .
I know Q2 got around that as well with the Chaingun's second spin, and from what I've seen in the sourcecode, the same fire pattern is applied a second time but with a 0.05 delay. Thing is, I have no idea how to accomplish it, can anyone help me on that?
Also, the weapon is supposed to fire at every two frames, the inbetween are for cosmetic purposes (meaning it'll fire as fast as the NG/SNG), and I intend to apply the same fire programming seen from the Nailgun/SNG (where the fire trigger is tied to the animation)
 Variables For Storing Persistent Info Between Maps
#1723 posted by Kinn [31.54.196.82] on 2015/09/30 11:24:07
I know we once had a long discussion about the most efficient and safe way to store information between maps (say if one was to try to make a hub-style continuity across maps) - anyone remember this, and got link to the posts?
 Kinn
#1724 posted by FifthElephant [82.24.73.240] on 2015/09/30 12:10:58
Not sure about that but I'm pretty sure Socks mod new mod has a better way to do this now.
#1725 posted by Lunaran [24.180.199.42] on 2015/09/30 17:44:09
Daya - view weapon anim is driven by the player model's animation state, which is crappy. there's not-insignificant reengineering to be done to decouple them.
Kinn - parm1-parm16.
 Kinn,
#1726 posted by FifthElephant [82.24.73.240] on 2015/09/30 17:57:44
 Got Most Things Working For The Infantry Gun
#1727 posted by Daya [86.192.38.52] on 2015/09/30 18:24:04
Now there's a last thing, and it's about def.qc, where it stores the weapon slots. Taking http://www.insideqc.com/qctut/qctut-7.shtml as face value, I put "17" as a value for my weapon. Now thing is, it opens the grenade launcher icon, while I want it to be on the 4th (NG) one. I tried "5", but it also adds me the Nailgun when I pick up my weapon on the testmap. Tried other values like 3 and 7 but I always have other weapons added on pickup. How can I deal with this?
 Copy Paste
#1728 posted by Preach [77.99.55.146] on 2015/09/30 19:44:59
If you want it to be on the nailgun slot, copy the value that the nailgun has there. You basically have to replace the nailgun by stealing its slot, copying the values etc. If you want the nailgun as an alternative then you need to do a lot more complicated stuff, for starters just replace everything to do with the nailgun with your new code.
 Cf. Scourge Of Armagon, With Proxymine Launcher
#1729 posted by Daya [86.192.38.52] on 2015/09/30 20:52:47
I looked at said sourcecode (both weapons.qc and hipdef.qc) and the weapon switching code is the exact same (see http://pastebin.com/7bUga8cy ). Even with that I still can't choose the gun by pressing 4. What the hell!
 Parms Abuse
#1730 posted by Kinn [109.147.139.107] on 2015/09/30 21:46:20
Cheers chaps, that post by Preach was the stuff I was looking for
 Data
#1731 posted by necros [173.199.65.60] on 2015/09/30 21:54:24
your code says 'if i have the nailgun, switch to the infantry gun, otherwise switch to the nailgun' which makes no sense.
 Source Of Confusion
#1732 posted by Preach [77.99.55.146] on 2015/09/30 23:34:56
There are lots of places to get confused in the weapons code. The first is the difference between .items and .weapons.
You'll have spotted the way that the IT_ codes are taken from the sequence of doubling numbers:
1,2,4,8....
That's to make each of them have a single 1 digit in binary:
0001,0010,0100,1000...
This lets you add a set of them together into one number, and get the bit flags back afterwards:
1101 = 1000+0100+0001 - the point is that you can work out what "single digit numbers" to put on the right, just by looking at the number on the left. It wouldn't work with just any set of numbers (the trick is called bitflags if you want to google it).
So that's how .items work, it can store all the items the player has picked up in a single number, just because of how the bitflags add up. On the other hand, the .weapon field only needs to be able to store one weapon at a time, so there's no reason it couldn't use 1,2,3,4,5 as the codes for the weapons. It basically uses the same codes as .items out of expedience.
Well...ok, that last bit is not strictly true, but it's a very useful way to think about the QC code in isolation. Enter the second confusing thing about the .items and .weapon system: as well as being the way that the QC handles the player inventory, these fields have "side effects" which affect the HUD. So the binary digits which are 1 for the .items value turn on weapon slots. When .weapon is the equal to the value of one of the item slots, that weapon is lit up on the HUD.
So the side effects stuff is a bit hard to keep track of, but it gets worse. The third confusing thing is that the expansion packs wanted to alter the HUD, but originally it all works automatically as "side effects". So if you run engines in -hipnotic or -rogue mode, the HUD changes behaviour! Different numbers of weapons/powerups appear, an extra field called .items2 controls some behaviour...it's a real hacky mess.
So I return to my original suggestion. Initially, just make a weapon that replaces the nailgun. This will be challenging enough to get to grips with, and once you've done that, you'll be in a much better shape to understand the changes in the hipnotic code and how to bring the nailgun back.
 Found A Way To Keep Both
#1733 posted by Daya [86.192.38.52] on 2015/10/01 00:04:21
By pretty much writing 4 possibilites, depending on what the player holds. "No weapons" shows up when pressing 4 with either the nailgun or the infantry gun hold, but for now I don't care.
Now, the absolute final thing: how do I make the hitscan attack draw a small trailpuff like Q2 Weapon Factory's Mega Chaingun? I've been told to make some sort of loop to make it happen, but that only made things more confusing for me. Any help on that one?
 Parms Follow-up Post
#1734 posted by Preach [77.99.55.146] on 2015/10/01 00:37:31
In my parms blog post a short way above, I linked to a bug that can cause you to lose runes when you load a save file and then decide to restart the level instead. I've devised a way to work around this bug in QC, and posted it tonight:
https://tomeofpreach.wordpress.com/2015/09/30/fixing-runes-and-restart-with-qc/
There's not much insight to it besides fixing the bug, but you should go and copy-paste the code anyway...
 High Level Smoke Puff Trail
#1735 posted by necros [173.199.65.60] on 2015/10/01 05:07:56
use this shotgun tempentity code to create the puff:
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
look at code for temp entity stuff, the last 3 lines are the x y z coords and org_? is the vector variable.
create a loop that iterates along the vector generated by the traceline that is detecting damage for hits and such at regular intervals and spawn the temp entity from the above code (make a vector variable called 'org' as referenced in the code).
to iterate, get the vector and normalize() it then multiply that unit vector by increasing amounts until you are past the end point.
#1736 posted by Daya [86.192.38.52] on 2015/10/01 11:19:06
That's the thing though, I know mostly nothing about programming, and your reply just make me ask more questions, like "How do I write such a loop and where do I implement it?" and "Wouldn't this effect be too big considering I want to control the particles amount and spread?" and "Wouldn't using gunshot impact effect look bad in Darkplaces, considering it replaces the puff with an actual bullet impact GFX?"
#1737 posted by necros [173.199.65.53] on 2015/10/01 17:36:40
http://www.tutorialspoint.com/cprogramming/c_while_loop.htm
float len = vlen(endpos - startpos);
while(len > 0)
{
//do whatever effects here
len = len - 16; //do it spaced out by 16 units
}
#1738 posted by Kinn [109.147.139.107] on 2015/10/02 19:18:51
Another "been a while since I did this shizzle" question:
What QC compiler are the kool kids using now, is it FTEQCC? If so, where is the homepage/link to latest version pls? (google throws up a host of dead/shady links)
#1739 posted by JneeraZ [174.109.106.46] on 2015/10/02 19:21:15
I just use whatever tools are on ericw's page ...
http://ericwa.github.io/tyrutils-ericw/
 Warrenm
#1740 posted by Kinn [109.147.139.107] on 2015/10/02 19:31:11
Ah yes, for map compiling absolutely - but what I was wondering is what QC compiler is the current hotness.
 Kinn
#1741 posted by mfx [78.55.174.120] on 2015/10/02 19:37:05
 Mfx
#1742 posted by Kinn [109.147.139.107] on 2015/10/02 20:12:35
Noice, that's just the ticket
#1743 posted by JneeraZ [174.109.106.46] on 2015/10/02 20:31:51
Oh lord, sorry. :) Reading, hard, blugh...
 A Gun That Winds Up, Shoots, Wind Downs
#1744 posted by Daya [90.1.212.222] on 2015/10/12 23:23:47
So I've been trying to code my weapon today, and it's a Gatling Gun composed of 3 states: a wind up, a shooting loop, and a wind down.
The programming's supposed to be like this: weapon.qc holds the code to play sounds, and player.qc holds the animation (the W_Attack part in weapons.qc calls the starting animation in player.qc, "player_gatlup1"), and both of them are supposed to sync.
weapons.qc: http://pastebin.com/kJ1mMtqC
player.qc: http://pastebin.com/Bnf4ThZ1
Problem is, in weapons.qc, I want the Gatling Wind Up part to go on for 0.9 second no matter what, and then switch to Gatling Shoot. And it seems like self.attack_finished isn't the way to go, but after the help I got I got more confused because I haven't been told of a workaround.
Would somebody be kind enough to help me on this?
 Spin Up
#1745 posted by Preach [77.99.55.146] on 2015/10/13 04:28:20
The traditional way would be to have a series of animation functions leading to the firing sequence:
player_gatlup1
player_gatlup2
...
player_gatlup9
and only player_gatlup9 sends you to player_gatlshot1. For this approach, I'd probably ditch W_GatlingSpinUp and import the sound cue into player_gatlup1. As an important side note, you don't need these lines:
self.nextthink = time + 0.1;
self.attack_finished = time + 0.9;
in your player_gatlup1 function. nextthink is set automatically to time + 0.1 when you start a function with the prologue [$light1, player_gatlup2], and as the later code sets the attack_finished time that portion is redundant.
Hopefully from there things should start to work, it is something that there's no natural example of in the Quake code so the approach isn't obvious. I called this the traditional way - once you've got that bit working, there is a way to reduce the number of functions back down, but perhaps for another day...
 Preach
#1746 posted by Daya [90.1.212.222] on 2015/10/13 15:37:52
Thanks, that made the weapon functionnal, but when I hold the shoot button, it indeed does the windup animation, but if I continue holding, it shoots a bullet, then does the wind down animation while still playing the gatling gun wind up sound on a loop. The windup, shoot a bullet, winddown routine goes on a loop until I let go of the button, when it'll imediately snaps back to its starting position while playing the gatling gun wind down sound once (the self.attacked_finished = time+0.9 is still in effect here).
Here's my reworked code from what you've said: http://pastebin.com/QbC7R7nT
 OK, My Apologies
#1747 posted by Preach [77.99.55.146] on 2015/10/13 20:09:04
I have a theory on what's happening. If the theory is true then I was wrong, the self.attacked_finished = time + 0.9 is doing important work I hadn't recognised, and I shouldn't have told you to remove it.
My theory is that you're not getting the wind-down animation, just jumping to the top of the wind-up animation, because your attack_finished time you set in player_gatlup1 just runs out when you make it to player_gatlshot1, and then the rest of the code decides that it's time to launch a new attack from player_gatlup1. So I think you should try putting some more self.attacked_finished = time + 0.9 in all the attack sequences, plus perhaps the last of the spinup functions.
As a side note, watch out for the function W_CheckNoAmmo. Although it looks like it's just returning some information to your function, it actually has a side effect of changing your weapon instantly! This will mean it skips your wind-down animation if you run out of ammo. Put a simpler check like self.currentammo > 0 in its place, and perform the weapon switching on the last frame of the wind-down instead.
 Some More Problems...
#1748 posted by Daya [90.1.212.222] on 2015/10/13 21:43:10
I added the self.attack_finished = time + 0.9 lines to the last 3 frames of the gatling spin up part, deleted "return" as a condition result for self.currentammo > 0 and instead put it in the gatling down's function once frame 34 is played (the last one, for when the weapon winds down).
Now if I just press the fire key once or hold it, the weapon spins up, and after it finishes its animation it shoots once (the fire animation's not playing like before), then goes back to its first frame, and the gatling firing loop sound plays once. I have to wait 0.9 second -it seems- to be able to fire again.
Geez, how did Team Fortress Software able to code the Assault Canon properly for QWTF?
 Patience Young Grasshopper
#1749 posted by Preach [77.99.55.146] on 2015/10/13 22:29:15
They wrote the code for the assault cannon exactly like this, except they did all the cursing in private and didn't show anyone until they'd got it to work.
One of the things that I've spotted:
void() player_gatldown1 =[$nailatt1, player_run ]
The bit that says player_run there means that 1 frame after you've started the spindown animation, you skip straight to "everything is normal" mode, besides waiting for the attack_finished counter to run down. You should change that bit to player_gatldown1 so that it keeps looping back to the same function. Of course, it will never return to "everything is normal" mode unless you add a line which runs player_run(); once the animation has completed, so add that too.
Are you getting a chain of shots in-between spinning up and spinning down, so long as you hold fire? I hope that's all working now...
#1750 posted by Daya [90.1.212.222] on 2015/10/13 22:39:32
I can only get one shot either by just hitting the button once or holding it.
After I did what you suggested, it can only fire once like I said (it did it before) and then the winddown function loops at one frame at a time, and I can't do anything weapon-wise until I pick up an item.
code: http://pastebin.com/wFj7j1cJ
 For Your Consideration
#1751 posted by Preach [77.99.55.146] on 2015/10/13 23:09:21
Please ponder the following two lines
self.weaponframe = 15;
self.weaponframe = self.weaponframe + 1;
When you see what is wrong you will see why you can't exit the spindown (besides collecting an item).
This still does not fix the 1 shot at a time issue. If you have added the attack_finished code to the player_gatlshot1 etc functions then I am stumped. It might relate to how the code interacts with the parts in other files you haven't posted....
#1752 posted by Daya [90.1.212.222] on 2015/10/13 23:38:10
I now have put self.attack_finished = 0.9 on each firing frames, and did as follows:
firing frames: hhttp://pastebin.com/ucD70L9N
gatling down: http://pastebin.com/x8nfUsRc
It still fires one shot no matter if I push once, or hold the trigger, or not push anything during the sequence. But the spindown animation now plays properly, as well as the sound.
Making it fire is now the last problem programming-wise.
 Also,
#1753 posted by Daya [90.1.212.222] on 2015/10/13 23:41:50
Because Gatling wind down is called every time a frame passes, the self.attack_finished I intended to be set on 0.9 is now too high, I have to wait for the whole animation to end before doing anything, while the idea is to wait for an animation cue to do things again weapon-wise.
#1754 posted by SleepwalkR [79.195.29.27] on 2015/10/13 23:42:22
They wrote the code for the assault cannon exactly like this, except they did all the cursing in private.
Nice.
#1755 posted by Lunaran [24.56.201.253] on 2015/10/14 00:30:46
is the qwtf source available?
#1756 posted by Daya [90.1.212.222] on 2015/10/14 00:38:43
It is, but last time I checked I couldn't understand how the Assault Canon actually worked, the code kinda looked messy.
 Removal
#1757 posted by Preach [77.99.55.146] on 2015/10/14 01:01:37
I think you are safe in getting rid of self.attack_finished = time + 0.9; from the wind-down part now, so long as it's set in each of the attacking frame you should get a decent wind-down which can't be interrupted, without a huge pause afterwards. If it's too short, change the values in the attack frames.
You have the ammo check the wrong way round in your attack frames btw, and I worry you may need more brackets. Can you try changing
if ((!self.button0) || self.currentammo > 0)
to look like
if ((!self.button0) || (self.currentammo <= 0))
That should stop you exiting after 1 shot. You may want to make those code blocks end with a return once more if that starts working, so that you don't fire an extra shot on the frame you released fire on/ran out of ammo on.
#1758 posted by Daya [86.192.97.145] on 2015/10/14 01:34:42
Thanks, I'll try to take it from here for now on, since there are fixes to be done.
Before that I should mention that adding "return;" to the end of each firing blocks doesn't fix the problem of firing an extra bullet before exiting/skipping the firing pattern.
Also, the firing loop sound still plays if it's still on the set timer after switching to the spindown part. I assumed the winddown sound would play over it, since they're on the same channel. This obviously has something to do with self.t_width, but I don't know what condition it takes to say "if mingn2 is playing, play mingn3, else play mingn3" in the spindown block.
 Fix
#1759 posted by Preach [77.99.55.146] on 2015/10/14 01:38:42
Before that I should mention that adding "return;" to the end of each firing blocks doesn't fix the problem of firing an extra bullet before exiting/skipping the firing pattern.
Add it to the if block that decides if the sequence is ending, not the whole function.
#1760 posted by Daya [81.250.248.102] on 2015/10/15 01:27:42
OK, so the Gatling Gun i've been coding this past few days now works flawlessly, it's great. I can't thank Preach enough for his help.
I've been testing it in Darkplaces (like I did with the InfantryGun), but once I switched to Quakespasm the weapon doesn't appear at all. In fact he gives this error in the console:
http://image.noelshack.com/fichiers/2015/42/1444865216-spasm0005.png
So what gives? I don't think that's linked to the bit field I gave to it (it being "8388608" so it doesn't conflict with other items).
#1761 posted by metlslime [67.169.151.72] on 2015/10/15 02:09:38
is it case sensitive and you have inconsist case between the map file and the quakec?
#1762 posted by Daya [81.250.248.102] on 2015/10/15 02:30:17
I checked if it was a case of hitboxes changing between clients, like how powerups need to be lifted up to 16 units from the ground to appear properly. I tried that, but the error's still there.
 Looks Like Your Progs.day Isnt Loaded
#1763 posted by ericw [108.173.17.134] on 2015/10/15 02:45:46
 That Error
#1764 posted by ijed [186.9.135.70] on 2015/10/15 02:49:26
Means the qc being called doesn't exist.
So yeah, check that you haven't got an upper/lower case problem somewhere that Dark places was automatically correcting.
#1765 posted by metlslime [67.169.151.72] on 2015/10/15 06:23:02
the error literally means the classname in the map file doesn't match any spawn functions found in the progs.dat, which is why i suggested the upper/lower case issue. It could also be a spelling issue (though can't explain why it would work in darkplaces then) or maybe the progs.dat isn't even being loaded (perhaps darkplaces has different rules about folder searchpaths or valid filenames for it?)
#1766 posted by Daya [81.250.248.102] on 2015/10/15 10:04:23
That was it, when I transferred the files from darkplaces to quakespasm I forgot to transfer the progs.dat file.
Thanks again for your support!
 Mdl Winding Sanity Check
#1767 posted by Kinn [86.190.22.173] on 2015/10/18 00:02:26
Can anyone tell me what the correct winding order is for quake .mdl triangles? (CW or CCW?). It's not a big issue because I can reorder my vertices to switch the winding, but the fact that my tris are coming out flipped is baffling me a little bit.
 Pretty Sure It's CW
#1768 posted by SleepwalkR [87.146.57.67] on 2015/10/18 08:34:19
 Resetting Think Fields
#1769 posted by Preach [77.99.55.146] on 2015/10/27 23:32:26
Imagine you would like to reset an entity which has already had a .think function set; this lets you use the same check for a entity which currently has no thoughts as one which has never had any. Then imagine that you were overly paranoid about how airtight your solution was, and you wrote in an incredibly pretentious manner. The result might be something like https://tomeofpreach.wordpress.com/2015/10/27/eternal-sunshine-of-the-spotless-think/
 @Preach
#1770 posted by Spike [81.147.0.240] on 2015/10/28 00:37:34
Or, if you're using FTEQCC there's a handy c++ism.
self.think = 0;
you can also use __NULL__ if you want to make it look a little less bugged.
 __NULL__
#1771 posted by Preach [77.99.55.146] on 2015/10/28 00:42:58
Is the 0 thing a new feature? I get a pointer/integer type mismatch with my current version. Just tried __NULL__ and that works well.
#1772 posted by Spike [81.147.0.240] on 2015/10/28 01:33:51
newer than __NULL__ anyway (aka: 0i).
 Integer Constants?
#1773 posted by Preach [77.99.55.146] on 2015/10/28 08:04:34
Is that a way of getting actual integer constants then? Might be an interesting trick I can get out of them if so...
#1774 posted by Spike [86.191.128.189] on 2015/10/28 16:01:34
denorm = (__variant)5i;
denorm20 = 4*denorm;
float4 = denorm20 / denorm;
if you omit the __variant cast then it does an implicit int->float conversion. if its not a known constant then it'll attempt to use extended opcodes / builtins.
with the cast, it'll use a direct store, resulting in a denormalised float (ie: a really really small float, that has the same bitpattern as a positive int of up to 23 bits, just much smaller).
I'm sure you're aware of this, but for other readers, multiplying a float by denormalised 1i 'converts' that float into a denormalised pseudo-int. you can then add two such pseudo-ints together using standard fpu operations and then convert back into floats with division.
you can use this for evil hacks like field indexing or function indexing.
I would caution against doing this for a few reasons.
1) fte's field remapping (as part of its nq+qw hybrid support) tends to break any assumptions about known offsets, so be sure to not hardcode any specific offsets nor expect them to work correctly over 'recognised' (aka: remappable) fields.
2) there's no way to directly reference globals other than to hack some entity to index its fields into quake's hunk memory. this will be caught by fte,dp,qf, and will need inconsistent offsets in various other engines.
3) its basically unreadable.
4) denormalised floats are often not supported or are emulated and thus incredibly slow. x86 cpus do support them in hardware, but intel chips are known to have significant performance slowdowns with them. itanium does NOT support them, even when running x86 code, while amd chips don't have any issues, yay amd.
I'm unsure about hardfpu arm chips.
fteqcc does support int operations, if you try using them with vanilla opcodes, it will promote mixed-type operations to using floats, and generate function calls for pure-int operations and casts. supposedly, at least versions that support func=0 anyway.
-fassume-int causes fteqcc to assume that ALL non-floating immediates are int types rather than floats. This is supposed to be useful to JIT type qc execution, but also makes quakec more c-like, if anyone wants that. 5.0 is still interpretted as a float.
 Something Like That
#1775 posted by Preach [77.99.55.146] on 2015/10/30 00:30:38
The old fastqcc stuff with indexing fields and pretending to get dynamic arrays seemed a bit desperate and risky, particularly today with all the different and complex custom engines about.
What I really wanted was some way to do a static vtable in Quake, without needing an entity to store all the functions in. I thought I might be able to make some kind of jump table with a bunch of return statements, and use an integer parameter to select of many of them to skip over.
It doesn't seem to work though, even though the stumbling point appears to be confusing the variable holding the jump distance with a label name to goto. Is there a better way of doing that which I'm missing? Can you index a block of consecutive functions if you define them all in succession?
 omg
#1776 posted by necros [109.201.154.208] on 2015/10/30 02:10:49
you are totally crazy, you know. any sane man would just use entities and be done with it!!!
 wait
#1777 posted by necros [109.201.154.208] on 2015/10/30 02:20:04
i assumed you were trying to fake OO?
 Preach
#1778 posted by Spike [86.191.128.189] on 2015/10/30 13:46:48
void() foo = {code;};
is really this:
var void() foo;
foo = numfunctions;
functions[numfunctions] = {code;};
numfunctions++;
or in other words, for functions to be consecutive, it is the function bodys that need to be consecutive, not their prototypes.
this makes assumptions about function ordering quite annoying in practise.
QC has no variable-distance jumps. If you want static vtables you're probably best just making an array and indexing in to that. I'm unsure how you would cope with assigning offsets though. And of couse, touch and think functions wouldn't work very well with it.
Which is why fteqcc's class stuff just uses fields for its virtual functions, and in doing so it can cope with thinks, touches, etc with ease (including engine-specific extensions, so long as they've an appropriate .void() or whatever def outside of a class for them to inherit from). nonvirtual calls are still direct calls of course. however fteqcc does only provide single inheritance, and constructors are designed to mirror spawn functions rather than traditional constructors.
class foo : entity
{
string myname;
virtual void() think =
{
dprint("I'm thinking here\n");
};
void() foo =
{
if (!myname) myname = "unnamed";
dprint(myname, "'s spawn function\n");
nextthink = time + 1;
};
};
void() calledfromsomewhereelse = {foo bar = spawn(foo, myname:"TheTest");};
class members use some weird name mangling (unless inherited from the basic entity type), which can make them problematic in maps.
there's only one extension used, and that's that it uses 'spawnfunc_foo' to fill in the stuff and call the constructor. this is used so that you can just call spawnfunc_player() inside ClientConnect without any issues about any player classes (you shouldn't really use this trick unless its known to be a non-class entity, as it doesn't reset any class fields, and aliasing between classes would leave unpredictable values).
dammit, another essay.
 Cheers
#1779 posted by Preach [77.99.55.146] on 2015/10/31 01:21:24
for functions to be consecutive, it is the function bodys that need to be consecutive, not their prototypes.
This sounds helpful rather than harmful, you don't need to worry that someone ahead of you in the compilation list prototypes one of your functions and mucks up the order. I hear what you say about entities being much more sensible for things with actual state, but I think there's a niche here which it could fill. Thanks for the post!
 Binary Saves And Dealing With New Versions
#1780 posted by necros [46.166.188.221] on 2015/11/11 05:22:08
non-quake question... say you are saving some data into a binary file. let's say preferences. somewhere along the line you may add in some new feature with accompanying preferences.
how do you deal with this when you need to read the old binary data and do a one time upgrade? do you just keep your old loading method and use the first byte to identify which loading method to use? is there a better way?
#1781 posted by metlslime [50.150.122.79] on 2015/11/11 05:55:54
you can create an extensible format... preferences are a list of key + value, so in theory you just want to add new key/value pairs over time. You either want a directory at the beginning of the file that first has "number of entries" and then an array of offsets to each entry, and then each entry can have a standard format, or you can have fixed size entries and just keep reading until you hit EOF, then you don't need a directory.
Either way, when reading the file, if it doesn't have all of the entries you expect you can just use the default value for the missing preferences.
Question: why do you want it to be binary?
 Sound
#1782 posted by madfox [84.84.178.104] on 2015/11/11 07:10:24
What can I do to prevent a new model,
that is jumping up and down to cause the
client.qc line : 849
void() PlayerJump =
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
sound?
#1783 posted by necros [46.166.188.221] on 2015/11/11 07:15:39
Question: why do you want it to be binary?
I want it to be portable (eg: no registry keys) but I don't want the user messing with things.
 Sound()
#1784 posted by madfox [84.84.178.104] on 2015/11/11 07:26:27
Actually I ment,
how do I stop the sounds h2ojump.wav / dland2.wav
for a new model playing in game?
 Necros
#1785 posted by SleepwalkR [79.195.19.187] on 2015/11/11 07:39:13
Google for flatbuffers.
 Then Become FB Friends With Aardappel
#1786 posted by Lunaran [24.56.201.253] on 2015/11/11 07:53:37
 MadFox
#1787 posted by Spike [86.169.39.250] on 2015/11/11 08:07:25
cvars...
sv_sound_watersplash ""
sv_sound_land ""
these two cvars exist in dp+fte, probably not other engines.
self.contentstransition = someemptybutnotnullfunc; can be used as an alternative for the watersplash sound, but its more awkward and probably no better supported.
@necros: just use base64 on a text file or something. key+value pairs are good for forwards compat (even if were to use key+valuelen+valuedata blocks in a binary format, embed the version of data as part of the key or something).
 Maaaaaaaaaaadfox O____O
#1788 posted by necros [66.249.83.232] on 2015/11/11 15:37:30
I replace those sounds with silent .wav files!
 ...anyway
#1789 posted by necros [172.98.67.17] on 2015/11/11 19:17:36
settled on a pretty simple method. i have just assumed that the order of stored prefs will always be the same, and anything new will be added to the end.
this way, i can just go ahead and read things in with default values if we're at EoF as in metl's suggestion. but this way i don't need any kind of headers or whatever.
FlatBuffers looks cool, but I like to avoid using extra libs when possible, although that looks like it'd be very useful for more complex systems (eg: games) so thanks for the heads up!
 Necros
#1790 posted by SleepwalkR [130.149.243.224] on 2015/11/12 10:23:22
Yeah, that sounds like proper YAGNI design ;-). However, I wonder why you don't want users to be able to edit the prefs?
 Also
#1791 posted by SleepwalkR [130.149.243.224] on 2015/11/12 10:23:45
Of course they're still able to do so, you're just making it a bit harder for them.
#1792 posted by JneeraZ [76.182.53.183] on 2015/11/12 12:59:15
There's a thin layer of amusement in the concept of someone on a Quake editing message board talking about ways to prevent users from tinkering with their settings and preferences. :P
#1793 posted by Kinn [86.175.217.138] on 2015/11/12 13:36:16
What's it got to do with Quake?
 The Best Thing I've Read Once Upon A Time
#1794 posted by onetruepurple [213.227.95.2] on 2015/11/12 13:48:49
Advocating for removing console access for the player.
#1795 posted by JneeraZ [76.182.53.183] on 2015/11/12 13:49:53
Nothing, directly. But the openness of Quake and how it allows hacking at pretty much every level, which makes this community possible in the first place ... And then necros is determined to lock his users out.
THAT'S ALL! Just found it slightly amusing.
#1796 posted by FifthElephant [213.205.251.94] on 2015/11/12 13:59:19
Pfft entitled quakers thinking they should be allowed to change stuff
#1797 posted by Kinn [86.175.217.138] on 2015/11/12 13:59:37
Maybe the idea is to edit the prefs via the program interface (won't break things) instead of typing whatever in a text file? (will break things)
 Yeah, Pretty Much
#1798 posted by necros [66.249.83.228] on 2015/11/12 14:02:05
You guys should see it soon anyway. :P
 Cvars
#1799 posted by madfox [84.84.178.104] on 2015/11/13 06:29:38
I searched for the use of this statement, but didn't get much further in QCman or Quakewiki.
I have no idea how to use it or where I should place it in the qc to make the two sounds silent.
It's about a dopefish, that tumbles in and out of the water, but the side effect is, that it produces the landing bounce of the demonfiend and the watersplash in quiet an anoying way throughout the level.
I could replace these sounds with silent.wav, but then other use for entities gets lost and that is not my intention.
#1800 posted by Spike [31.54.143.2] on 2015/11/13 09:12:29
tweaking those two cvars (via the cvar_set builtin or via default.cfg) is basically equivelent to replacing the wavs with silence.
and silence works in more engines, so either go with silent wav files or just live with the noise.
 "while" Loop On A Monster Attack As Long As The Target Is On Sight
#1801 posted by Daya [90.47.231.46] on 2015/11/13 10:28:48
I'm continuing on my singleplayer mod, and after the two guns I made I finished doing the assets of the Nail Infantry (now reduced to an enforcer reskin, trying to fuse the original model with another one spawns more difficulties than necessary), all I need is a tweak for the attack so that he attacks like the ChainGunner in Doom 2, as in he continues firing as long as the target is on sight.
I know for one thing it's something like "while ["target" is on sight"]=>[attack sequence]", but how should I write "while ["target" is on sight"]"?
#1802 posted by Lunaran [24.56.201.253] on 2015/11/13 18:49:36
if(visible(self.enemy))
don't use while, or he'll dump all his ammo in a single frame. or, use while just to see that happen first.
 Personally
#1803 posted by ijed [186.9.129.52] on 2015/11/13 18:57:28
I'd have him cycle between a few frames of animation - one which fires the projectile and one which checks to see if his target is visible. And then either some padding frames in between to make it less likely that he stops afiring s soon as the player is out of sight, or store a value and use a counter to do the same, resetting the count each time he starts firing again.
You might want to look at the scrag shooting - it has a couple of clever ideas in there, like firing at where the player was before they went out of sight.
You could get leading from chthon as well, but leading sucks.
 Paralyze
#1804 posted by madfox [84.84.178.104] on 2015/11/14 20:35:29
Maybe I'm not the first one that comes up with the idea, but would it be possible to give a monster an attack that freezes the player?
Just for a few frames, one second would be enough. I imagine it would be strange effect, because for the player it would be as if the game screen blocks, while after that time monsters would be on a different place. If the player survives the damage meanwhile.
Maybe it is just an insane idea, with all that crap like server messages and all, but anyway.
Would it even be possible?
#1805 posted by necros [172.98.67.46] on 2015/11/14 20:54:17
It would be, but would probably be quite complex.
If you just need to make it look like monsters have moved while you were standing still, you could duplicate all monsters and replace them with stationary models with the same frame, angles, etc...
Then, make the real monsters temporarily have no model (change to a sprite with 255 frames and a transparent image) and keep running ai functions as normal.
then, when the effect ends, remove all the fake monsters and restore the normal models to the real monsters.
but yeah, very complex.
 Ah
#1806 posted by madfox [84.84.178.104] on 2015/11/14 21:33:44
feels like an Alice touch.
I think I first go for a bucket of coffee in the AIcafe before I start that!
Thanks anyway!
 Rotten Cells
#1807 posted by madfox [84.84.178.104] on 2015/11/14 22:55:54
I made a cell ammubox bsp that leaks.
It shows up in game by adding it to items.qc.
What does it need to fool the player, so it won't charche an amount,
or better make the amount less?
For now it works just like ammu_cell adding 5.
 Monster Spawning Properly In Maps
#1808 posted by Daya [90.47.231.46] on 2015/11/15 14:16:09
So I've done coding for my chaingunner-like, he's visible in TrenchBroom, but when I play the map he's nowhere to be seen. I assume it's because I missed some qc file that stores monster classes, or at least a qc file that stores the qc files themselves, but as far as I know I can't find such a thing.
I followed this tutorial: http://www.insideqc.com/qctut/qctut-49.shtml and instead of telling what's the proper way to spawn an independant monster, he just tells to just replace a monster. That's shitty.
 Classnames
#1809 posted by Preach [77.99.55.146] on 2015/11/15 15:00:54
Hi Daya, I may be teaching you to suck eggs or whatever, but here's the basic idea that lets you spawn an entity in Quake:
classname in the map editor corresponds to a function name in QC
So if you look at the function called monster_shambler (in shambler.qc), the instructions there are followed at every point that you add an entity to your map whose classname is monster_shambler.
So if you've already written the code for your monster, you should have an equivalent function in your qc which sets the health, model, animations etc for your chaingunner. If you have called this function monster_chaingunner, you need to add an entity whose classname is monster_chaingunner. If you can't get that working, rerun your map with "developer 1" in the console and look out for the error message
 Bonus Post
#1810 posted by Preach [77.99.55.146] on 2015/11/15 15:19:08
The linked tutorial commits a sin, a subtle but important piece of bad design. If you run the mod, load a map and find a mage, make a save game. If you keep reloading the game, at random all the models will go wrong when you load a save game. Why?
Well, it's because of the randomisation, which will occur differently each time you run the map. The save file does not actually stored the list of precached models, and instead regenerates it by loading the map from scratch, before loading the saved data. Whether the first monster on the map is a mage or a vore will change the order of precaches, and if the decision goes different ways between the initial load and the re-load, you get mismatched models!
There are a few ways you could fix this. You could precache all the models for the vore and the mage before rolling the dice to see which one you get. You could make the method of switching pseudo-random rather than random so that the same order occurs each time you load the map. The important lesson is that when it comes to the map initialisation sequence, you can't allow anything random to affect a precache.
 No Dice
#1811 posted by Daya [90.47.231.46] on 2015/11/15 15:54:46
I forgot to mention I based my coding by making a copy of enforcer.qc and did the modifications fromp here. I actually did that "monster_nailinf" stuff before, and tried to remove the 2s the precache code had from the enforcer code, but still to no avail.
Running darkplaces with "developer 1" in, and it says this:
http://image.noelshack.com/fichiers/2015/46/1447599239-infantry20151115155014-00.jpg
I'd also like to note the guy's supposed to be following pathcorners in front of me, if that information can help.
#1812 posted by necros [66.249.83.83] on 2015/11/15 16:01:36
Is it included in the progs.src file?
 Nalinf.qc Included While I'm At It
#1813 posted by Daya [90.47.231.46] on 2015/11/15 16:04:00
 Necros
#1814 posted by Daya [90.47.231.46] on 2015/11/15 16:08:50
Thank you, that was exactly what I was looking for! Now the monster spawns with no problem.
Now the only thing that needs fixing is the idle sound and death sound not playing, as well as the rate of fire and him stopping shooting when the target's dead.
#1815 posted by necros [66.249.83.80] on 2015/11/15 16:33:27
Idle will only play when walking, not standing. And you precached death but play death1.
 One Last Thing
#1816 posted by Daya [90.47.231.46] on 2015/11/15 17:13:51
in the line that checks if the target is on sight, how should I write "or if the target's health equals or is inferior to 0"?
 More Like "or If The Target's Health Is Superior To 0"
#1817 posted by Daya [90.47.231.46] on 2015/11/15 17:18:18
 Code
#1818 posted by Preach [77.99.55.146] on 2015/11/15 17:28:36
if(self.enemy.health > 0)
It translates into code quite directly. Also you want use AND here, not OR, because you only want to continue firing if your enemy is visible and is alive, so in total you need:
if(visible(self.enemy) && self.enemy.health > 0)
 Thanks A Lot Preach!
#1819 posted by Daya [90.47.231.46] on 2015/11/15 17:49:29
 Opening A Can Of Worms
#1820 posted by Daya [90.47.231.46] on 2015/11/16 11:35:19
So the next step in my mod is to add my lines of code into the latest quoth release by decompiling it. I could stop here and just have the Infantry Gun, Gatling Gun and Nail Infantry, but for what I want to do I'd love to use quoth's expansion as well as my stuff on top of it, stuff like more base monsters (or hell, more monsters in general), rotating doors, teleporting enemies... all of that good stuff.
So I've been doing a bit of research. I tried this: http://quakeone.com/files/10-miscellaneous/95-mrelusives-quakec-compiler-1999/ but it says the directories don't exist despite what seems to be a clean command line ("path to progs.dat" -d). Then I red this: http://www.quakewiki.net/archives/botshop/code/plus.txt and downloaded said software. When executing it, Windows says the program is not compatible with my current version of W8.1.
Going back to the first software, I grabbed its progs.dat on the software's directories, but it says after analyzing progs.dat "DEC_CalcProfiles - No parameter names with offset 377".
Anybody can help me there?
 Man, Is Decompiling Such A Taboo Thing?
#1821 posted by Daya [90.47.231.46] on 2015/11/17 10:01:13
#1822 posted by Spike [81.151.32.74] on 2015/11/17 10:47:31
"DEC_CalcProfiles - No parameter names with offset 377".
that basically means that the qcc stripped out the names (and very probably types too) of locals.
this means that if you can find a decompiler that makes stuff up, you'll still end up with what is basically gibberish.
You do NOT want to have to maintain that.
I have a private fork of frikdec which will try to decompile anything. nothing is fatal, it just writes out a best-effort instead. which is gibberish.
I don't give it out for a few reasons:
1) I don't want the flak from modders pissed at me for opening up their closed mods.
2) I don't want to have to maintain it.
3) I REALLY REALLY REALLY DO NOT want to have to help other people get it to compile.
4) any encouragement to get people to work on decompiled code is a baaaad idea.
5) unmodified frikdec is good enough for most purposes. mods that it can decompile generally have enough usable hints to not result in gibberish.
6) this way madness lays.
years ago, I did toy with the idea of 'appending' to a progs.dat file. load an existing progs, compile some new code, write out a new one with the extra code added (with some functions wrapped or whatever).
I didn't get very far with it though.
by the way, decompiled code sucks.
 Daya
#1823 posted by Kinn [86.175.217.138] on 2015/11/17 15:40:07
If the mod is closed source, your best bet is to approach the authors and ask nicely.
Decompiling isn't really the way forward.
 Changeroll ()
#1824 posted by Teknoskillz [50.136.116.163] on 2015/11/17 18:58:39
Anyone know where I can find a good QC written function for this one that ID left out? I found one in another forum but its usinf a function called anglemod_view () which has a lot of while statements and seems prone to runaway loops. Mostly because it seems to have problems with a 360 degree roll.
 Private Spoon
#1825 posted by madfox [84.84.178.104] on 2015/11/17 22:11:19
Sorry for the Malice progs.dat
Even when the ones that created feel sorry now for their encriptment.
 Kinn
#1826 posted by Daya [81.250.125.67] on 2015/11/18 13:43:17
I sent Preach an email about that subject yesterday evening. I'm waiting for his response.
 Compiler
#1827 posted by khreathor [88.156.136.240] on 2015/11/18 20:39:32
What QC Compiler would you recommend nowadays?
 Fteqcc
#1828 posted by ericw [108.173.17.134] on 2015/11/18 21:19:05
#1829 posted by necros [66.249.83.83] on 2015/11/18 22:42:41
I think it's the only modern one..?
 Don't Call It Monsterclip...
#1830 posted by Preach [77.99.55.146] on 2015/11/18 23:14:41
New blog post, detailing how to create func_player_clip, and func_nonplayer_clip, which are solid only to players and non-players respectively.
https://tomeofpreach.wordpress.com/2015/11/18/selective-clipping
It's not technically monsterclip, because it is solid to other things as well. But as long as you use clipping brushes, the set of non-player things which will collide with them and the set of monsters are essentially identical.
Bonus material (cut from the post): There may be a small opportunity for a bug here with hitscan weapons, pain functions with walkmove on the first frame and very unfortunate positioning, but I don't think stock monsters can encounter it. Still, a cookie if you can figure out where it is and how to avoid it...
#1831 posted by Spike [81.151.32.74] on 2015/11/19 02:29:52
two players enter a server.
the first player says 'I'm off'.
so the postthink says 'oh, in that case I'll make the other player into a monster'.
you probably want to use setorigin instead of setmodel. its more efficient for what you're trying to do. just leave the .modelindex set and clear out .model
in fte or dp, you don't need to do any relinking.
additional: will not work in fte, dp, or any quakeworld server. in these engines, player thinks are typically out of sync with monsters in order to facilitate prediction.
not when playing coop or deathmatch, anyway.
 Two Players Enter, One Player Leaves...
#1832 posted by Preach [77.99.55.146] on 2015/11/19 19:37:29
two players enter a server.
the first player says 'I'm off'.
so the postthink says 'oh, in that case I'll make the other player into a monster'.
But the player entities are reserved in a block at the head of the entity list, so the slot is only freed up for another player.
My potential worry is that if you attack a monster with a shotgun, that might trigger a pain animation. Frame 1 of that pain animation plays instantly, and if the monster moves the physics occurs immediately. Since we're still within the call stack of the player functions, this gives the monster chance to walk inside an info_nonplayer_clip while it's non-solid, and land up stuck afterwards. It would be better if pain functions never called frame functions, but just set them as a think to happen immediately, but you can't make that change centrally so it's fiddly to do.
you probably want to use setorigin instead of setmodel. its more efficient for what you're trying to do. just leave the .modelindex set and clear out .model
in fte or dp, you don't need to do any relinking.
That's cool, noted. I don't know those corners of the engine well enough to know what you can get away with, and what's too much of a hack for some future engine to bear.
additional: will not work in fte, dp, or any quakeworld server. in these engines, player thinks are typically out of sync with monsters in order to facilitate prediction.
not when playing coop or deathmatch, anyway.
But do those engines let players execute thinks out of sync with each other? The idea is that the natural state of things is non-solid func_player_clip, and solid func_nonplayer_clip. Any time the engine runs physics on the players, we invert the natural order, then swap it back before physics runs on anything else. This is safe so long as all the players get acted on in a block, separate from all the other entities, even if the frequencies differ.
If the engine might ever run the physics on one player but not the others straight after, then the optimisation needs to go, and we must toggle the solidness after every individual player. Piles yet more inefficiency on in coop, but its the price of correctness.
#1833 posted by Spike [81.151.32.74] on 2015/11/20 04:26:18
nextent skips entities that are free, correct...
But player entities are never free even if there's not a player in them. nextent thus finds player entities even if there are no players.
this means that flags&FL_CLIENT is unreliable, if not for the map the player leaves on then it definitely will be for the map that comes after.
pre/postthink won't happen for the first/last player slot if there is no player in it.
player entities are run out of order in quakeworld engines. the server runs player physics only when a network packet has been received from the client in question. this ensures that the entity state the server replies with is actually correct with regard to the state the server acknowledges.
this is done out of sequence because with 4 players it would otherwise require up to 288 physics frames per sec (assuming an infinitely fast server, less if the server's cpu is a bottleneck as multiple clients+packets may be serviced between waking periods).
removing the nextent optimisation would indeed also solve this case.
note also that touch events will fire between pre+post think (as well as during walkmove+movetogoal), and may get into an inconsistent state that way. whether this is actually a problem depends on the rest of the mod.
 Noted, Cheers
#1834 posted by Preach [77.99.55.146] on 2015/11/20 22:14:39
Did not know that about empty player slots, but that's certainly a no-go then. I've amended the post to remove the optimisation, it's actually a much easier read now!
Re: touch being another issue, agreed, but like you say it's something that's only an issue based on the mod. Essentially it's movetogoal and walkmove that are the troublemakers - bits of code which set velocity etc. on an entity don't matter as the physics they set in motion isn't evaluated immediately.
A particularly brutal way of dealing with that threat would be a wrapper which simply causes walkmove/movetogoal calls to automatically fail if made during player physics! Both functions can already fail is the monster is blocked, so there's no guarantee of success for any call. It's mighty tempting, even if it's not all that pretty...
 Re: Player Slots
#1835 posted by Teknoskillz [50.136.116.163] on 2015/11/23 19:54:54
I have found that nextent (world) will be player slot #1 (colormap 1) and nextent from there is player slot #2, all the way down to your max players setting. This is when doing it outside of Worldspawn () ... for it seems during worldspawn, its also setting up what they use to term as "Quaked" entities or the maps entities....and I dont believe the player slots are set up yet, or they may be inaccessible - but I could be wrong. Its been a while since I experimented with that...I was trying to create a cvar that flags the server as dedicated or local and I believe the 1st player could not be found in worldspawn using nextent.
 Tempstring Error
#1836 posted by Teknoskillz [50.136.116.163] on 2015/11/23 20:02:38
If we strcat a corpse's netname to be that of its owners netname such as:
corpse.netname = strcat (corpse.owner.netname, " s dead body");
Notice the "\n" is left off the end...
Now if we eprint that corpse, I believe a tempstring error will pop up in the console because netname requires a newline, and there is none. Also the netname field does not appear in the eprintout, nor will it appear using prvm_edict blah netname at the server prompt?
#1837 posted by Spike [109.145.178.137] on 2015/11/24 06:30:50
nextent skips over free entities. possible player entities are never free, even if the 'player slot' is. thus nextent will ALWAYS find player entities, but will find other ents only if they're not free.
the lack of a \n is irrelevant for everything other than displaying a newline when the string is actually printed.
entity dumps should display newlines in marked-up form - ie as a literal \n.
strcat returns a temp-string. temp strings are so named because they are temporary.
they are forgotten at some engine-defined time, either when the builtin is next called, when the builtin is called 16 times hence, when the engine returns to the caller, or when there are no more references to the string. there is at least one engine that implements each ony of these possible behaviours that I've listed.
tldr:
except for fte, all quake engines require you to use strzone for pretty much any temp-string which is assigned to a global or field (to avoid memory leaks you'll also need to use strunzone once you're done with it - but only if it isn't null, just to make things more awkward).
there are possible exceptions, but these tend to bite you later when you try saving the game.
#1838 posted by Lunaran [66.235.55.196] on 2015/11/24 11:00:39
Is there some more elegant way of handling click-and-drag inputs in an event-driven context than "set an isDragging boolean to true on mousedown" and making a big branchy state machine out of it?
 Use The State Pattern
#1839 posted by SleepwalkR [82.159.145.210] on 2015/11/24 11:48:56
It's the same principle, but without the switch/case cascades.
 Re: Tempstrings
#1840 posted by Teknoskillz [50.136.116.163] on 2015/11/24 19:10:02
@ Spike - thanks. If we have used strcat in that way on a netname field for an ent, and we strzone it, do we need to unzone if remove () is called on that ent?
 @Teknoskillz
#1841 posted by Spike [86.180.169.195] on 2015/11/25 12:15:43
technically yes. you'll leak otherwise, at least for the rest of the map.
whether that's an issue is a different matter. probably you won't leak that many strings so it won't be a problem. if you're allocating new ones every single frame, its more likely to be a problem.
 Floats/Booleans
#1842 posted by Daya [90.47.230.77] on 2015/12/03 18:47:36
So for my Gatling Gun I decided to change the sounds, and now the firing loop sound is designed to be 0.8 seconds long, that means it should play once every 2 times the shooting animation loops comes in.
What I had in mind was to use a float/boolean value, define it as such:
float() gatlingsound =
{
TRUE;
};
But quakec doesn't seem to like it, neither with those:
if (gatlingsound = TRUE)
sound (self, CHAN_WEAPON, "weapons/mingn2.wav", 1, ATTN_NORM);
---
if (gatlingsound = TRUE)
gatlingsound = FALSE;
else
gatlingsound = TRUE;
So what's the correct way here?
#1843 posted by Spirit [80.187.111.155] on 2015/12/03 18:53:11
No clue about quakec but
1) gatlingsound = TRUE surely would be an assignmen, not a comparison?
2) float as Boolean?!
#1844 posted by Daya [90.47.230.77] on 2015/12/03 19:04:40
Went looking for an equivalent in the quakeC manual, it said "float" was it.
Or maybe I misred it and it's something else?
#1845 posted by Lunaran [66.235.55.196] on 2015/12/03 19:19:16
there's no booleans or integers in quakec, float is what you get.
also, spirit is right, "if (gatlingsound = TRUE)" sets gatlingsound to true and then returns true 100% of the time.
why are you doing this?
float() gatlingsound =
{
TRUE;
};
are you trying to define a variable named gatlingsound? because this is a function declaration.
just trigger the sound on every 8th frame of the animation, you don't need to faff with this at all.
#1846 posted by Preach [77.99.55.146] on 2015/12/03 19:32:29
2) float as Boolean?!
In QC everything is a float - like javascript!
Spirit is correct that your test should use a double equals sign like:
if (gatlingsound == TRUE)
If your compiler doesn't warn you about this then you should get a newer version of FTEQCC.
Also, I think your definition of gatlingsound is a bit confused. What you have defined is not a variable to store a value. It's a function. It isn't even quite a function which returns "TRUE", because you've missed off the return command.
What you want to do is:
.float gatlingsound;
This adds a new variable to the player called gatlingsound. You have to access it as "self.gatlingsound = FALSE" and "if(self.gatlingsound == TRUE)".
That should get you compiled. You may find it doesn't delay the sound very much, but you'll be at the right point to look at the example of invisible_sound for how to do longer delays.
 Lunaran
#1847 posted by Daya [90.47.230.77] on 2015/12/03 20:39:08
I can't play the sound as you said, because the firing animation is played 1 frame every 0.05 second, meaning it would only play half the firing sound every time the animation loops.
And I just can't get the thing to work, even with "==" (it says "==" is not a name). Tried to replace TRUE and FALSE with 1 and 0 while changing "float" with "void", but the same errors always came in: "local functions may not be initialized" (is also said when I still use TRUE and FALSE while using == on everything but the declaration line) for the declaration line, and the rest is "unknown value "galtingsound"".
 Preach
#1848 posted by Daya [90.47.230.77] on 2015/12/03 20:45:02
Your thing got compiled. Thanks!
 @Lunaran
#1849 posted by Teknoskillz [50.136.116.163] on 2015/12/04 21:06:48
float() gatlingsound =
{
return (TRUE); // add return
};
if (gatlingsound == TRUE) // single = is an assignment , double is a comparison
sound (self, CHAN_WEAPON, "weapons/mingn2.wav", 1, ATTN_NORM);
else
sound (self, CHAN_WEAPON, "weapons/normal_gun_sound", 1, ATTN_NORM);
Also realize CHAN_WEAPON is not the same as CHAN_AUTO , so if there is another sound playing on CHAN_WEAPON, it will be overrided as well as another sound on the channel being able to override yours in code executing past the function you are putting it in.
 Gatlingsound ()
#1850 posted by Teknoskillz [50.136.116.163] on 2015/12/04 21:11:24
Sorry, the () is required otherwise it might cause that compile error:
if (gatlingsound ())
// pretty sure this will proceed only if true, but I have seen cases where negative intergers cause a true in some engines , IE: -1, -2 etc.
 Lmao
#1851 posted by Kinn [86.155.172.32] on 2015/12/04 21:13:23
float() gatlingsound =
{
return (TRUE); // add return
};
Can we just agree this is dumb as hell and not do it like this?
Just use a constant.
 Soundbuffer ()
#1852 posted by Teknoskillz [50.136.116.163] on 2015/12/04 21:23:53
Also, I have made soundbuffers in my mod but using just the basic sound command "play" stuffed to the console. I suppose it could be done with regular sound calls, best to define a special sound channel for it though, IE : CHAN_BUFFSOUND = blah
Where blah is the sound channel number. Darkplaces suppoert up to 128 sound channels total, not sure if other engines expand the sound channel range.
Basicly:
.string buf1,buf2,buf3,buf4;
.float sounbuffer
So you play the first sound, then call a new function that lists all the possible sound strings that the playing sound can be, and returns a float value equal to the total time it takes to play the sound in seconds, for each given sound. Then -
self.soundbuffer = time + SUB_SNDLEN (current sound);
In PlayerPRethink () , you add
if (self.soundbuffer < time && (self.buf1 != "" || self.buf2 != "" || self.buf3 != "" || self.buf4 != ""))
SUB_ChkSndBuffer ();
From there you just make the new function that checks all 4 buffers if a string is present. If so, clear that buffer with a null (""), and send that old string over to the function to play a buffered sound. that function also needs to scope through all the buffers in order in the even lost of sounds are stored.
 Most Engines Have 7 Xhannels
#1853 posted by necros [64.233.172.233] on 2015/12/04 22:33:40
1 to 7 are explicit and 0 is whatever is free.
Of course, you can just spawn new entities and have unlimited channels.
#1854 posted by Spike [86.161.56.215] on 2015/12/05 00:27:06
actually, that's a common falacy.
channel 0 is not 'whatever is free', its a 'don't terminate anything'.
of course if you do play lots of sounds at once then things can get VERY LOUD, which is why stuff tends to use an explicit channel, especially if the later half of the sound is a little echoy such that it sounds stupid when you have multiple instances playing with 0.1 sec intervals.
there may still be a global limit on the total number of sounds that can be playing at once, but thanks to static sounds this is typically quite a high limit (read: thousands).
 It's Okay Guys
#1855 posted by Daya [90.47.230.77] on 2015/12/05 00:57:21
Preach's way was compatible with what I wanted to do, and it goes as expected and flawlessly.
But still, thanks for your attention.
#1856 posted by necros [172.98.67.107] on 2015/12/05 02:05:00
i have also noticed if you try to play the same sound twice in the same frame, the engine will ignore it (or play at half volume?).
the only way around that i've seen is to create two separate .wav files that are identical and play the "different" sounds at the same time.
#1857 posted by Spike [86.161.56.215] on 2015/12/05 14:47:35
if you start two sounds at once on the same entity (on different channels) all you will have done is to double the volume.
with different ents, you will have spacialisation differences so there is still a purpose, but it will still be extra loud.
FTE does randomize the start time of the second sample slightly (this is something q2 also does). This tends to make it a little more echoy without making it quite so obnoxiously loud - more sounds means that it'll *probably* be louder, but this isn't guarenteed as the time difference will negate this effect by a not insignificant amount so volume 1.2 or so instead of 2.0.
This is the sort of thing you want if you have 20 identical monsters all seeing you in the same frame.
It can also potentially help in deathmatch too.
 Z-aware Grenade Shooters?
#1858 posted by Daya [90.47.165.131] on 2015/12/15 18:47:09
I'm continuing on doing monster reskins, and I want to make an Enforcer that's similar to the Defender, but I want it to shoot grenades while being Z-Aware, unlike the Ogres, and maybe make it explode on contact (they'll have to be weakened if I want to do that).
I remembered Inside3D/InsideQC had a tutorial for that, but for some reason I can't find it.
Can anybody help me on that case?
#1859 posted by Lunaran [66.235.55.196] on 2015/12/15 21:20:53
#1860 posted by madfox [84.84.178.104] on 2015/12/16 05:08:23
I remembered Inside3D/InsideQC had a tutorial for that, but for some reason I can't find it.
Try this one,it's not hijacked:
http://www.insideqc.com/qctut/
 Thanks Lunaran, Also
#1861 posted by Daya [92.155.135.3] on 2015/12/16 11:34:46
I did a Grunt shooting accelerating rockets, I tried to make in a custom explosion sound, but it plays the vanilla one instead and the explosion sprite doesn't come up.
code: http://pastebin.com/0aBFGkFP
Another thing, still on that Defender-like: how to make him trigger an attack where the player is in a set distance? Looking at the Ogre code doesn't seem to answer me.
and MadFox, this is exactly where I went, but I couldn't find it.
 Another Thing
#1862 posted by Daya [92.155.135.3] on 2015/12/16 12:00:53
What's the way of reducing the amount of stun taken by a hit for a monster? Is it related to armor values?
 .th_pain Or Pleasure
#1863 posted by Preach [77.99.55.146] on 2015/12/16 12:28:34
You need to look at the function in ".th_pain". Two good examples are knight_pain and sham_pain.
Typically there are three decisions to make in a pain function. The first is whether the monster had a pain animation recently or not. Usually this is a bit of code like:
if (self.pain_finished > time)
return;
self.pain_finished stores the first moment the monster is allowed to go into pain again, and this code skips a pain animation entirely if it's too soon. This is a very important bit of code because it stops pain animations overlapping - without it you'd have monsters entirely stunlocked by a stream of nails.
The second choice is to decide if the damage is high enough to trigger pain. Typically only very large monsters do this, like the shambler:
if (random()*400 > damage)
return;
This means we skip the pain animation randomly, in proportion to the damage inflicted. For example, a shambler will only go into pain from a 200hp hit 50% of the time. A full double-shotgun blast does ~50hp, so that's only a 1-in-8 chance of a pain animation. 400+ hp in one blow will always cause shambler to go into pain, but even a quad rocket to a shambler isn't powerful enough for that.
The last choice is selecting which pain animation to use, here's the code for the knight:
r = random();
if (r < 0.85)
{
knight_pain1 ();
self.pain_finished = time + 1;
}
else
{
knight_painb1 ();
self.pain_finished = time + 1;
}
The line knight_pain1(); start this pain animation immediately, and it will run to the end before the monster starts attacking again. The main difference between these two animations is that knight_painb is much longer. A way to make the pain animations less severe is to pick the short animations more often, so the monster resumes fighting earlier.
You'll also notice that it's this part of the code which sets the pain_finished time, in this case saying the knight won't go into pain for 1 second. The enf_pain is an elaboration on these ideas, as there are 4 pain animations to choose from, and the last one has a longer pain_finished time than the other. So another way to make your monster resistant to pain is to increase these times, but be careful! Setting these too high made the Quoth monsters irritating to fight, as they were too relentless.
 Ogres Lob Grenades Into Cover
#1864 posted by Teknoskillz [50.136.116.163] on 2015/12/16 23:28:38
...is what I believe the original post on inside3d was. Me and Prime collaborated on this into Gnouc's clean src a while ago into a creepcam2 project. IT seemed to work pretty good from what I remember, and I thnk we put in a skill comparison to activate it as well. YOu can copy the code from the Ogres function here: [ https://github.com/teknoskillz/Creepcam2/blob/master/monsters/ogre.qc ]
 Right Handed LG Pos
#1865 posted by Teknoskillz [50.136.116.163] on 2015/12/17 03:18:00
Trying to _perfect_ as best as possible the starting pos of the LG beam using a right handed vwep model sort of like the one in dpmod has. The tricky part is finding a compromize between the 1st person view, and the external viewposition. I believe there is no perfect fit, but this is the code I am experimenting with in W_FireLightning ()
local vector angl;
// angl = self.v_angle;
angl = self.angles;
normalize (v_forward);
org = ((self.origin + (v_right * 7)) + ((v_up * (10 + ((angl_x * -1) / 3)))) + (v_forward * (12 + (((0 - angl_x) / 1.05)))));
I believe the problem may be v_angle versus angles, as the first person view will always be using the v_angle perspective, and using .angles definately manages the external view better so far in my experiments.
Just curious if anyone ou tthere knows a better way? Im using Darkplaces as the engine and it has a waist level lightning option in the menu but on or off does not seem to show much difference in this case.
#1866 posted by Lunaran [66.235.55.196] on 2015/12/17 10:22:25
that's going to change based on engine, right? fitz engines use a different weapon offset than other engines, and it's positioned differently when you look up or down.
 CSQC
#1867 posted by kalango [177.134.146.47] on 2015/12/17 12:48:56
Hey, anyone knows any resource for learning CSQC? Mostly HUD related CSQC. Every link i find seems to be dead.
Also i wanted to know if FTE supports CSQC for Hexen ;P
#1868 posted by Baker [65.60.224.195] on 2015/12/17 13:14:38
 Thanks For The Help On Grenade Lobbing, But
#1869 posted by Daya [92.155.135.3] on 2015/12/17 14:20:02
I'm still looking for a way for monsters to change attacks depending on its distance with the target/player
 You Need
#1870 posted by ijed [190.22.34.36] on 2015/12/17 14:35:53
A Choose Attack function.
Look at the bottom of the monster where it's Ai routines are initialised, you should find something like this:
self.th_stand = ogre_stand1;
self.th_walk = ogre_walk1;
self.th_run = ogre_run1;
self.th_die = ogre_die;
self.th_melee = ogre_melee;
self.th_missile = ogre_nail1;
self.th_pain = ogre_pain;
All the ones which have a '1' at the end are sending the monster to that animation sequence whenever the conditions are met. The others have a routine which decides which animation sequence to send them to, like this:
void() ogre_melee =
{
if (random() > 0.5)
ogre_smash1 ();
else
ogre_swing1 ();
};
So instead of just going directly to ogre_smash1(); it has a 50% chance of going to that OR ogre_swing1();
 More On Choosing An Attack
#1871 posted by Preach [77.99.55.146] on 2015/12/17 18:47:32
There's a good template to base your attack choosing decision on in SoldierCheckAttack. The first half of the function is basically checking if the player is visible. Look at the bits afterwards involving enemy_range - they set a variable chance of attack according to player distance.
You'd want to adapt that so it changes the attack itself rather than just the probability. I'd change the bit which uses self.th_missile to directly name the attack I want to use. e.g:
if (enemy_range == RANGE_NEAR)
{
alien_spit_acid1()
return TRUE;
}
else if (enemy_range == RANGE_MID)
{
alien_fire_rocket1()
return TRUE;
}
return FALSE;
There's an important extra bit of the puzzle here, in order to get a custom checkattack function you need to add it to CheckAnyAttack. Otherwise you get the default CheckAttack, which only gives you the choice of 1 melee attack and 1 missile attack.
 @kalango
#1872 posted by Spike [86.135.244.26] on 2015/12/17 19:37:27
FTE servers translate stuff such that the client can't really tell whether its hexen2 or quakeworld with a certain set of extensions.
so yes, fte+csqc+hexen2 should work fine on the condition that you can work with the extra stats that the server sets up to provide whatever hud functionality normally expected for a q2 mod.
for those stats, check http://sourceforge.net/p/fteqw/code/HEAD/tree/trunk/engine/common/bothdefs.h for the STAT_H2_ enum values.
you can override or add to these inside your SSHC code, if you need.
huds are otherwise 'just' a case of calling drawpic+drawstring etc.
the tiny font can be selected with drawfont=loadfont("", "gfx/tinyfont", "8", -1);
then switch drawfont between that and -1 or something.
its otherwise just a glorified quake mod.
#1873 posted by Daya [92.155.135.3] on 2015/12/17 23:22:04
Had to use Preach's method for Grenade lobbing because FTEQCC doesn't recognize "makevectors2" nor "grenade_velocity", but even with that and the HTML rewrites he doesn't recognize attack_elevation.
 You Need To
#1874 posted by ijed [190.22.59.24] on 2015/12/17 23:28:23
Add those to defs.qc.
Add them to the end of the list though, too high up and you change things the C code is expecting to be there.
 Declaring Variables
#1875 posted by Preach [77.99.55.146] on 2015/12/17 23:47:50
Daya, there's a general programming idea here which seems to be tripping you up. The idea is called declaring variables, here's a short tutorial on it.
https://www.macs.hw.ac.uk/~pjbk/pathways/cpp1/node45.html
When the compiler is complaining about names it doesn't recognise, it usually means you're missing the declaration. You may need to add the declaration, or you may need to move it earlier in the file. You can also get this error if you misspell a variable, so check the spelling of the error and the declaration carefully.
Incidentally, the declaration for attack_elevation is right below the sentence
"Finally we need to change the ogre’s firing sequence to make use of all this new code:"
you may have have copy-pasted that bit incorrectly...
 Yeah But
#1876 posted by Daya [92.155.135.3] on 2015/12/17 23:51:00
What types of declaration should I put "grenade velocity" and "High_GrenadeFly(dist)"?
#1877 posted by Daya [92.155.135.3] on 2015/12/17 23:52:33
Forgot to tell I decided to use Teknoskillz' method because Preach's method doesn't seem to work, as the shooters still aren't Z-aware.
 Tried The Following Declarations:
#1878 posted by Daya [92.155.135.3] on 2015/12/18 10:45:54
vector grenade_velocity;
float grenade_velocity;
void() grenade_velocity;
(He always says "float should be vector")
and
float (vector v) High_GrenadeFly;
vector High_GrenadeFly;
(He mostly says "Bad field type")
I feel like I'm dumb as bricks, christ
#1879 posted by kalango [177.134.214.1] on 2015/12/18 17:28:36
Thanks for the info on CSQC guys!
 GrenadeLobbing Issue: Resolved
#1880 posted by Daya [92.155.135.3] on 2015/12/18 20:38:10
I remembered an old unfinished mod I made when I first started QuakeC modding, and the Ogre's code contained said Inside3D's grenade lobbing tutorial code, which was actually small.
I feel relived now, as this issue just made my development came to a full stop.
 Mastery
#1881 posted by ijed [190.22.116.248] on 2015/12/18 20:50:15
The difference between a novice and a master is that the master has made more mistakes.
 @Daya
#1882 posted by Teknoskillz [50.136.116.163] on 2015/12/19 03:39:25
The code I linked to was from the inside3d article...it may have even been in the AI area to make FRikbot lob the grenades, not sure. I dont recall who was the author, but I can say for sure in the coop game mode with monsters, the ogres determinately are improved using that code. Glad you got it working tho.
 OK What The Hell
#1883 posted by Daya [92.155.135.3] on 2015/12/20 22:40:19
I've been working on an Ogre-like that shoots a flak-burst of nails, I only took out the grenade code and replaced it with said flak-burst of nails, but the problem comes to the chainsaw part of all things, where FTEQCC says at the very end of the declaration it's "incompatible".
http://pastebin.com/YyARaT2Z (at line #113, at the very end of the chainsaw declaration, "};") It's the same chainsaw code from the ogre's file that I never touched, I guess that's why "FIX ME" is written there but if that's the case I don't know what's the solution.
 Debugging Advice
#1884 posted by Preach [77.99.55.146] on 2015/12/21 01:02:39
It's really a good idea to post the exact text of the error message you're getting, although posting all the code is also helpful.
My guess is that you've still got a function called chainsaw in the original ogre code, and the identical copy in your new is confusing the compiler. Functions should only be defined once, so I'd recommend just deleting the copy from this new file - the definition from the old file will be fine if you haven't made any changes.
 Sorry,
#1885 posted by adib [201.22.114.8] on 2015/12/21 05:14:33
this nail flak-burst Ogre is not a Quoth monster you used on "Escape from Your Cell"?
 @Daya
#1886 posted by Spike [86.145.140.137] on 2015/12/21 05:30:26
'incompatible redeclaration' means you defined something twice, but with different types.
the error should include some kind of note that says where the previous definition/prototype can be found, while the error line itself says the new/later redeclaration of it.
just make sure they both have the same type (and only one initialisation, ideally).
like preach says, you probably already have some existing function/field/monkey with the same name elsewhere with a different purpose, in which case just rename one of them or something.
Alternatively you can prefix both defs with the 'static' keyword so that they won't conflict with other definitions from other .qc files.
 With What Preach Said,
#1887 posted by Daya [92.155.135.3] on 2015/12/21 10:10:23
I remembered a solution I did before when something similar happened with animation declarations: I just had to rename them according to the monster's name.
@adib I'm not using it, I'm recreating it with my own code as far as I can, with a different skin and sound set.
 Function Reuse
#1888 posted by Preach [77.99.55.146] on 2015/12/21 18:25:08
But Daya, if both of the functions are identical apart from the name, wouldn't it make more sense to just use the same function in both places, and make sure that there's only one definition? I'm worried from your response that my explanation didn't make sense...
 Oh No I Got It
#1889 posted by Daya [92.155.135.3] on 2015/12/21 19:18:40
Like, I could've deleted the chainsaw code inside butcher.qc, and the declarations would actually mention the one in ogre.qc, but I didn't do that simply for keeping things in their own sides, even if there's no changes.
 Yes
#1890 posted by ijed [186.9.134.241] on 2015/12/22 18:50:25
Duplicate entries are anathema for pro coder's - typically you want to keep only one function but make it more complex, so it would know which monster was calling it (butcher or ogre).
But the format of the QC doesn't help, since some attack functions are in weapons while many others are scattered across all the monsters.
One of the things we did in RMQ was to add an attack library qc, and then move everything to that one central location.
 At Least
#1891 posted by ijed [190.22.29.2] on 2015/12/22 21:16:59
That was the intention, to make everything modular. We got quite a way before the project collapsed.
The strength of a system like this is that your code is easier to debug and more open - if you decide to chop and change abilities or add new ones its pretty easy.
Especially since, in quake at least, almost all the projectile creations are the same apart from a few different variables like damage done, model used and so on.
 Dir = Aim(self, 1000);
#1892 posted by Teknoskillz [50.136.116.163] on 2015/12/25 21:37:14
Is there any difference in the aim built in function than merely calling makevectors on your v_angle / angle and assigning :
dir = v_forward;
??
Or does the aim function do that but normalize the result? Also whats the float of 1000 or whatever you enter there actually do ?
#1893 posted by Spike [86.176.35.37] on 2015/12/25 21:58:08
aim typically returns v_forward.
traditionally it also nudges the z value to point towards entities with .takedamage==DAMAGE_AIM
this gives the same sort of aiming found in doom with its complete lack of pitch angles.
of course, because this means peoples rockets always miss the enemy's feet, most engines default sv_aim to 2 or so in order to disable the autoaim/automiss effect.
#1894 posted by Lunaran [24.180.199.42] on 2015/12/25 21:59:20
What does 2 do as opposed to 0?
 Actually Looked
#1895 posted by Lunaran [24.180.199.42] on 2015/12/25 22:13:03
It's just a dot product comparison, which means sv_aim is actually fully on instead of off.
 I Want To Know As Well
#1896 posted by ijed [186.9.133.236] on 2015/12/25 22:14:08
Esoteric but interesting.
#1897 posted by Spike [86.176.35.37] on 2015/12/26 00:00:11
for fun, set sv_aim to -1 then try to do rocket jumps with a monster in the same room (including behind you) :)
 Sprites!
#1898 posted by Daya [86.192.37.192] on 2015/12/26 21:45:55
So it seems I got the hang on sprite thingies, but I don't know how to properly integrate them.
From my observations on the explosion sprite, this is what I came up with: http://pastebin.com/DzipzBRq
 Compiling And Logic
#1899 posted by Preach [92.233.91.91] on 2015/12/26 22:38:24
I'm guessing that you want the plasma to animate while it flies, let me know if not.
The first problem is plasmashot1...etc are functions, but you have defined them in the middle of the LaunchPlasma function. Move those above the rest of the code and it should compile.
The second problem is that you aren't using them, you need something which says self.think = plasmashot1 to kick off the animation. Change the line for SUB_Remove to plasmashot1 instead and change self.nextthink = time + 0.05. Then you should get animations.
The third problem is that SUB_Remove never gets run, and so plasma might stick around forever. This is actually a bit harder to sort out, because we can only have one think function at a time, and we're already using it to run our animation. How can we schedule a think for 5 seconds in the future if we need to think 20 times a second in the meantime?
The nice thing is that your code will run without fixing this, so have a think about it first and I'll explain in a later post.
 LaunchPlasma ()
#1900 posted by Teknoskillz [50.136.116.163] on 2015/12/27 05:34:54
Yea, Daya, I dont think you can compile voids within other voids...but, ok for some reason FTE compiler allows you to do that. I tested and even though it lets you compile a void in another function, if you try calling that void, the compiler catches it and does not really see it defined. So those frame macros for the plasma sprite need to come out of there and go somplace else, such as in player.qc where other frame macros are. Funny thing you found tho !
#1901 posted by Spike [86.176.35.37] on 2015/12/27 10:09:21
nested functions are meant to be a thing, but I'm still getting the kinks out. thanks for finding one of them.
either way, writing lots of nested animation/state functions isn't really advisable, especially if you're likely to use incorrect indentation.
 What Could They Be Used For?
#1902 posted by ijed [186.79.221.210] on 2015/12/27 17:13:13
Only running nested ones from within the main, like an exclusivity thing?
#1903 posted by Spike [86.163.87.85] on 2015/12/28 07:49:16
self.think = (void()){remove(self);};
is an example of an annonymous nested function.
they're good for simple callbacks and stuff.
reducing the number of top-level functions can make the code feel simpler and thus be more aproachable, plus it allows the callbacks to be nearer where they're used, which is a nice way to improve readability (when not abused).
unfortunately the qcvm allows no practical way to give callbacks access to the parent function's locals (unlike other languages may allow), but I can make an exception for static locals (which are really just glorified globals).
 First Test With Sprites
#1904 posted by Daya [86.192.37.192] on 2015/12/28 15:01:22
So, this is what happens: the monster does his routine when he sees me, but after he fires his first shot (he 's an enforcer type of monster, so normally he fires 2 shots consecutively) he's stuck in his idle pose and his animation goes twice faster than usual for this animation only. Attacking him makes him go back to his routine after doing his hurt animation though. The sprite's animation is stuck on the first frame, but it disappears when it hits brushes or entities, so that's that.
Here's the code:
http://pastebin.com/mq8ivUPU
#1905 posted by Spike [86.163.87.85] on 2015/12/28 15:49:49
self.think = plasmashot1;
you're mixing up your newmis and your self.
so that should be:
newmis.think = plasmashot1;
obviously this then conflicts with the following line that you have lower down:
newmis.think = SUB_Remove;
this is along the lines of what preach was talking about.
iirc sprites do also support framegroups, you might find those easier to tie in with remove timeouts, if you can find a tool to write those.
#1906 posted by Daya [86.192.37.192] on 2015/12/28 16:51:09
I'm using fimg, as suggested on the General Chat thread. How should I work this one out?
#1907 posted by Lunaran [99.46.64.63] on 2015/12/28 17:57:01
leave the sprite the way it is and fix the self references. there's nothing wrong with the sprite.
 Spike
#1908 posted by Daya [86.192.37.192] on 2015/12/28 18:37:39
Tried your thing, but the effects are the same as I've stated.
Code: http://pastebin.com/FwRPucgv
 Daya
#1909 posted by Preach [77.99.55.146] on 2015/12/28 19:22:10
He said to replace the line
self.think = plasmashot1
- you've left it in. You've also left in the line below
newmis.nextthink = time + 5;
newmis.think = SUB_Remove;
These will cancel out the newmis.think = plasmashot1 code. You need to have
newmis.nextthink = time + 0.05;
newmis.think = plasmashot1;
- plus have no other lines which change nextthink or think on either newmis or self.
 Oh, My Mistake
#1910 posted by Daya [86.192.37.192] on 2015/12/28 19:34:27
Now it works. Thanks a lot!
 Particles Are Harder Than They Look
#1911 posted by Daya [86.192.37.192] on 2015/12/29 15:42:12
Continuing on my super enforcer, I'd like for the projectile to spawn particles as it's flying in the game, and make particles scatter on impact.
So for the first part of this I went to the QuakeC manual and found said line to spawn particles: "void particle(vector origin, vector dir, float color,float count)". I tried "void particle(org, 0, 245, 7);" but FTEQCC doesn't like that I wrote "org", and putting "0" instead make the same results.
The idea is to spawn chunks of particles at a given time btw.
 Org
#1912 posted by adib [186.228.0.26] on 2015/12/29 15:46:06
is probably undefined, so 0 has the same effect.
 So What Should I Replace It With Then?
#1913 posted by Daya [86.192.37.192] on 2015/12/29 16:33:18
 A Vector!
#1914 posted by ijed [190.22.92.38] on 2015/12/29 16:37:51
particle (self.origin, '0 0 0', 228, 5);
Where do you need them? right where the thing is, so, self.origin.
Do you want them to move in xyz? Probably not because the bullet is moving, so '0 0 0' movement.
What colour? Maybe orange... 228
How many? Really it depends on how frequently it will produce them... 5 maybe.
 Note
#1915 posted by ijed [190.22.92.38] on 2015/12/29 16:39:50
If you do want to give them movement, the vector of the projectile will not be taken into account unless you do some vectormancy.
 Thanks Ijed
#1916 posted by Daya [86.192.37.192] on 2015/12/29 18:41:33
Now I need for the projectile to generate said particles, like the Vore's explosive balls. I looked into its file, but there's no mention of any particle line here, same thing for the rocket in weapons.qc.
 (please Ignore The Title Icon)
#1917 posted by Daya [86.192.37.192] on 2015/12/29 18:41:56
#1918 posted by onetruepurple [93.105.177.58] on 2015/12/29 18:42:50
The particles coming from the voreballs and rockets are features of their models, not the code. Your better bet is to look at the AD source code.
 Burst Of Particles
#1919 posted by Preach [77.99.55.146] on 2015/12/29 19:53:42
To get the explosion of particles when the projectile lands, you need to use the following rather unintelligible code:
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION2);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
WriteByte (MSG_BROADCAST, 35);
WriteByte (MSG_BROADCAST, 8);
The most interesting value to play around with here is the one currently set to 35. This controls the colour of the particles. The 35th colour in the palette is a pale blue, so that's the colour of the explosion, 144 makes it bright purple instead.
The following value sets the range of colours that the particles cycle through. At the moment, the value 8 means that we cycle through eight colours in the palette. In the example, the next 7 colours after the starting point are all slightly different shades of blue, so the effect is a slightly dappled effect. If you changed this value to 255 then you would get (almost) all the colours in the palette.
QC Quiz: What goes wrong if you set this value to 256?
#1920 posted by JneeraZ [76.182.53.183] on 2015/12/29 20:24:55
It wraps to zero and you don't get any particles? Or they're all black ... or something ...
 256 Refers To The Transparent Color, E.g There Won't Be Any Particles
#1921 posted by Daya [86.192.37.192] on 2015/12/29 20:34:02
 The Solution
#1922 posted by Preach [77.99.55.146] on 2015/12/29 21:26:10
It wraps to zero
Yes! As the function suggests, the value is packed into a byte, and so a value of 256 will be transmitted as zero instead. Based on the patch notes for darkplaces, I'd guess this will usually make the engine crash with a divide by zero error.
 TE_EXPLOSION And DP
#1923 posted by Daya [86.192.37.192] on 2015/12/29 21:34:22
TE_EXPLOSION2 doesn't exist (a trap!), so I changed to TE_EXPLOSION. Compiled it, run it, and when the projectile hits, this happens: http://image.noelshack.com/fichiers/2015/53/1451421144-infantry20151229213012-00.jpg
Is this an isolated incident to DP or did I made a mistake on just copy pasting your code?
#1924 posted by Spike [86.163.87.85] on 2015/12/29 21:42:43
#define TE_EXPLOSION2 12
it was created for rogue, so tends to not be pre-defined in vanilla id1 code, but it does work in all NQ engines (but not vanilla qw) if used properly.
 It's Nice But
#1925 posted by Daya [86.192.37.192] on 2015/12/29 22:02:00
It's like when I tried to make a custom explosion sound for a rocket soldier: the original explosion sound seem to always play whenever TE_EXPLOSION or any variant is called. There's also no burst of light and the particle spread, while blue like I wanted, doesn't look as good as the original one.
 Ah Yes, The Sound Trick
#1926 posted by Preach [77.99.55.146] on 2015/12/29 23:07:04
Yeah, it's annoying that the engine does that - there is a silly workaround though. Replace the sound/weapons/r_exp3.wav file with a silent sound like sound/misc/null.wav. Then you need to add the sound back onto the the grenade and rocket explosion by making a copy of the original sound and playing it manually.
 Thanks Again Preach, Another Thing
#1927 posted by Daya [86.192.37.192] on 2015/12/30 00:55:44
You said some time ago your website holds a way to make a monster spawner, much like how Quoth did. I did look for it in the Code section but I haven't found such a thing. Maybe the title is different, or it's not in the Code section?
 Quake Mp1 Laser Gun Laser Position Help
#1928 posted by Legend [99.29.61.114] on 2015/12/31 10:20:25
I'm trying to change the position of the lasers from mp1 to match the new quake 1.5 models. I've managed to correctly change the position of everything else. But looking at the code, I'm having some trouble figuring out where/how to actually change it.
I assume it is here:
=================
HIP_FireLaser
=================
*/
void(float stat) HIP_FireLaser =
{
local vector org;
local vector dir;
local vector out;
local float ofs;
local float aofs;
if (!self.button0)
{
player_run ();
return;
}
if (self.ammo_cells < 1)
{
self.weapon = W_BestWeapon ();
W_SetCurrentAmmo ();
return;
}
SuperDamageSound();
self.effects = self.effects | EF_MUZZLEFLASH;
makevectors (self.v_angle);
ofs = 6;
out = v_forward;
out_z = 0;
out = normalize(out);
org = self.origin + ((12-ofs) * v_up) + (12*out); // this is the value I have to change for the starting position?
// org = self.origin + (1*v_forward);
dir = aim (self, 1000);
aofs = ofs * 0.707;
if (stat == 0)
{
self.currentammo = self.ammo_cells = self.ammo_cells - 1;
org = org + (aofs*v_right);
org = org - (aofs*v_up);
HIP_LaunchLaser(org, dir, 0);
org = org - (2*aofs*v_right);
HIP_LaunchLaser(org, dir, 0);
}
else if (stat == 1)
{
self.currentammo = self.ammo_cells = self.ammo_cells - 1;
org = org + (ofs*v_up);
if (random()<0.1)
{
HIP_LaunchLaser(org, dir, 1);
newmis.dmg = 25;
}
else
HIP_LaunchLaser(org, dir, 0);
}
self.punchangle_x = -1;
};
 Looks Like It
#1929 posted by ijed [190.22.29.218] on 2015/12/31 11:34:06
 HIP_FireLaser ()
#1930 posted by Teknoskillz [50.136.116.163] on 2015/12/31 19:59:14
Yes, its where you commented. I went a little further and made a .vector vwep_pos , that merely points to that org vector in each of the weapon firing functions...so now its easy to know where a missile originated from with respect to the player.Its a little but weird because the Quake guy dont really hold the weapon up to his eye level like other games do, but alot of the tracelines in Quake start at eye position, and there is a difference depending on what knd of calc you wanna do.
Also, I have tried to make the starting point of the missile or the beam for the LG look just as good from the first person view , as from the outside of the model when firing. Its tough, and I dont think there is really a way to make it look exactly right...bleh.
#1931 posted by Spike [86.163.87.85] on 2016/01/01 10:22:34
@Daya
Little known hack for explosion particles without sound:
particle(pos, '0 0 0', 0, 255);
(direction and colour will be ignored, count must be exactly 255, pos is the middle, obviously)
 Blood Redscreen
#1932 posted by Teknoskillz [50.136.116.163] on 2016/01/10 22:01:31
Is there a way to disable or control the frequency of the red screen flash when the player takes damage? Apparently the QC is not doing a bf stuffcmd, so I guess this is done engineside? It sould be neat to setup the intensity based on the amount of damage taken...right now using Darkplaces, I cant find a setting for this and the effect seems the same no matter what the damage taken is.
#1933 posted by Kinn [86.151.102.31] on 2016/01/10 22:10:34
Dunno but sounds like the sort of thing that would trigger Smabler so go for it.
#1934 posted by necros [209.171.88.24] on 2016/01/11 04:10:08
Dmg_take controls red tint, dmg_save armour tint. Dmg_inflictor I think controls how the screen tilts.
 Quake 1 .bsp Lightmaps
#1935 posted by ALLCAPS [174.106.204.82] on 2016/01/11 09:27:07
Does anyone have some documentation they could link me on how lightmaps are stored inside the .bsp?
I'm trying to create a Quake 1 map renderer in Unity and lightmaps are sort of my final frontier.
I've found some conflicting documentation, most of which is vague. From what I gather the lightmaps themselves are simple arrays of values 0-255. I assume it's just a big lump of bytes, and the faces point into it to the start of their lightmap, but I do not know how to determine the size of any given face's lightmap. bspfile.h defines it as [numstyles*surfsize], but I'm not sure where to find or how to calculate a faces surfsize for this purpose.
Can anyone toss me a pointer?
#1936 posted by ericw [108.173.17.134] on 2016/01/11 10:24:17
Yeah, it's convoluted because they're not stored, you have to compute the lightmap sizes.
For each vertex on the face, you get the X and Y texture coordinates like this:
texcoord_x = (vert_x, very_y, vert_z, 1) dot (tex->vecs[0])
texcoord_y = (vert_x, very_y, vert_z, 1) dot (tex->vecs[1])
tex->vecs[0] and tex->vecs[1] are both vectors of 4 floats, tex is the texinfo_t* that has that's face texture alignment info.
Then, to get how many bytes wide/tall the lightmap is:
lightmap_width = ceil(max(texcoord_x) / 16.0) - floor(min(texcoord_x) / 16.0) + 1
lightmap_height = ceil(max(texcoord_y) / 16.0) - floor(min(texcoord_y) / 16.0) + 1
max(texcoord_x) is the maximum texcoord_x across all verts on the face. Hopefully I didn't mess anything up and the notation makes sense.
For reference this is the light tool code:
https://github.com/ericwa/tyrutils-ericw/blob/master/light/ltface.c#L355
#1937 posted by metlslime [50.150.122.79] on 2016/01/11 10:28:28
the engine source is probably the best documentation since it has code that reads, converts, and renders the lightmaps.
#1938 posted by Spirit [194.95.79.3] on 2016/01/11 11:21:46
Once you know, https://quakewiki.org/ would be a great host for that kind of information.
#1939 posted by [174.106.204.82] on 2016/01/12 01:53:22
I assume the notation above is dealing directly in the x/y coords of worldspace? I've already tamed the textures and mapping, if what I'm understanding is right, I should be able to use my existing code for decoding the texture UVs to do the lightmaps as well, with a little tweaking.
It was confusing because a lot of scraps I was finding were saying that lightmapping information/decoding was totally unrelated to texture UVs/composition, but it looks like that's not entirely true.
I'll give it a shot when I get off work.
Glad to see this place is still active. It was a huge help last time I worked on this project. It's the reason I've made it this far.
#1940 posted by ericw [108.173.17.134] on 2016/01/12 08:08:44
I assume the notation above is dealing directly in the x/y coords of worldspace?
Yeah, the vert_x, very_y, vert_z are worldspace.
texcoord_x/y are in texture space, and dividing these by the texture width/height gives the texture U/V coordinates normalized to [0,1] (except they go outside that range for repeating.) So yeah you should be able to reuse some of the texturing code for this :-)
btw as a sanity check, the lightmap_width/height values you get should be between 1 and 18.
 Hipnotic's Bullet Hole Sprite
#1941 posted by Daya [90.1.46.242] on 2016/01/12 11:30:54
Going further into properly integrating Scourge of Armagon's code into my mod, this time its sprites can't be properly compiled.
FTEqcc says "line9 - Unknown frame macro $spritename"
Here's the hipspr.qc file: http://pastebin.com/t0VypXAU
And yes, I made sure I also copy pasted the sprite files in the progs directory.
#1942 posted by metlslime [50.150.122.79] on 2016/01/12 18:08:47
that reminds me, i love that Jim Dose called it "QuickC"
#1943 posted by Spike [86.186.34.55] on 2016/01/12 18:41:52
Daya, skip that file (delete it or something), its not qc code.
(note how its not included in hipnotic's progs.src either)
 That Was The Solution, Yup
#1944 posted by Daya [90.1.46.242] on 2016/01/12 19:40:23
Gotta thank CZG for that
 Actually,
#1945 posted by Daya [90.1.46.242] on 2016/01/13 08:18:54
When the compilation went with no errors this time, bullet hole sprites still don't appear on brushes.
Even though I made sure to place the bullethole code in weapons.qc as well, so I really don't know what's wrong here.
In the end I can overlook that while developping the mod, but it's still annoying.
 Issues With Fteqcc
#1946 posted by kalango [200.19.186.55] on 2016/01/14 16:12:50
Ok so i'm trying to compile a hexen 2 and csqc project with fteqcc.
So, i can compile a standard hexen2 code normally, but if i try to put some csqc in it and link it with
#pragma sourcefile csprogs.src
in 'global.hc' the compiler complains with the following error:
": werror Q208: progs CRC not recognised from quake nor clones"
The thing is that if i compile the CSQC separately its all good, but i really dont wanna to have to do two compiles each time i want to compile the whole project.
Btw i'm using the command line fteqcc (same happens with GUI)
my compilation command:
>.fteqcc -src hc -Thexen2
And also, i'm using Hammer of Thyrion's HCode since i couldn't find anything better or updated...
#1947 posted by Spike [86.186.34.55] on 2016/01/14 21:02:07
put this in your hexen2 code (before any functions are processed):
#pragma target h2 //or fteh2, if you're going fteqw-only.
#pragma keyword enable thinktime
#pragma keyword enable loop
#pragma keyword enable until
and then remove -Thexen2 from your commandline.
alternatively, you can use
#pragma target id //or fte, because you might as well
in your csprogs.src, again before any statements are execed (keep the -Th2 bit if you're leaving the progs.dat code alone).
Alternatively, as you're not using fteqccgui anyway, you might as well just run fteqcc twice, with a batchfile or whatever.
fteqccgui is good for debugging though (which pragma sourcefile was implemented to simplify).
 Great!
#1948 posted by kalango [200.19.186.55] on 2016/01/15 13:56:59
I appended
#pragma target id
to the beginning of csdefs and it all went fine.
Thanks man!
 Darkplaces Water Twist/Movement
#1949 posted by Qmaster [50.45.39.173] on 2016/01/20 06:54:50
I can't for the life of me figure out how to enable the correct software quake style of rendering water with all its twisting and writhing in the Darkplaces engine. All the water does is scroll back and forth. I'm trying to dig through the engine code to find it. Its got to be somewhere...just disabled or commented out, right?
Anyone know where it is?
#1950 posted by Lunaran [66.235.55.196] on 2016/01/20 07:03:46
gl_subdividesize to 16 maybe?
 Something I'll Do In The Near Future
#1951 posted by Daya [83.192.155.253] on 2016/01/20 18:53:54
...cause right now I'm working on that BFG, but:
I'm planning on doing a Berserk power-up where attack speed is increased by 3 (weapon animation would speed up to reflect that) and ammo consumption divided by 2.
The question is, would such a thing be possible with something similar to SuperDamage? Especially with guns who are tied with their model animations (nailgun, super nailgun, thunderbolt)?
 Combining Shotgun Blasts?
#1952 posted by Teknoskillz [73.142.34.180] on 2016/01/23 19:58:39
Was just reviewing the old Qc src here: http://www.gamers.org/dEngine/quake/Qc/combat.htm
the part where it mentions combining shotgun blasts (in T_damage ()), seems to be related to the dmg_take field I was working on earlier. I know there is a multidamage work around on another forum.....but what was the original intent of multidamage? Its spawning an ent that basicly collects the damage and distributes it?
#1953 posted by necros [173.199.65.47] on 2016/01/23 21:47:27
the whole code is designed to reduce the amount of data being sent from clients and servers. instead of sending 50~ damage messages for small amounts, it sends 1 damage message with a large amount. if a shotgun blast hits multiple entities, then multiple damage messages are needed, but they still wanted to collect everything up as much as possible.
as a side effect, it basically lets shotguns gib monsters.
#1954 posted by necros [173.199.65.47] on 2016/01/23 21:49:48
edit: sorry, should have actually looked at the code you were quoting.
this is to make sure the screen tint looks the right brightness.
imagine you took damage from 2 sources in the same frame, A was 50 damage and B was 5 damage.
if you just set .dmg_take to whatever the damage was, and B was processed after A, then you'd take 55 damage but have a very faint red screen effect.
 Necros, Are You Implying Shotguns Gibbing Enemies Is A Bad Thing?
#1955 posted by Daya [90.58.20.133] on 2016/01/23 22:29:11
Going back to my last request, I know one way would be to have a (if BERSERK is active) check for each self.attack_finished, self.nextthink and ammo_counts for each weapons, but isn't there a more flexible option where potential added weapons could just benefit of just a function call, like what vanilla weapons do with the Quad Damage with SuperDamage(); ?
 @Necros
#1956 posted by Teknoskillz [73.142.34.180] on 2016/01/24 05:08:09
Yes, I was wondering more about the multidamage function moreso, but you answered both questions, thanks.
I'm futzing a bit with some QC that checks each bullets impact point on the client, and determines a rough "hitlocation" guesstimate based on some code that Muavebib made and posted a long while back. Its counting up the correct number of impacts to each body part ok, however I am also wanting to separate out the possibility its contacting multiple targets.
Basicly Im floating 2 local ents - a,b and c and put this code in the loop if we hit a .FL_CLIENT ent:
if (a == world)
a = trace_ent;
else
{
if (trace_ent != a && b == world)
b = trace_ent;
else if (c != a && c != b && c == world)
c = trace_ent;
}
...it sorta crudely works and isolates the correct trace_ent near the end of the function where I count up location impacts, but I suspect this wont work well on more than 2 clients. Its hard to hit a group of more than 2 usually , but just in case Id like to cover that possibility somehow.
Is it easier to modify the multi_ent in multidamage to do this?
 BFG Help
#1957 posted by Daya [92.155.135.241] on 2016/01/25 14:40:32
So I'm in the final stretch on doing that BFG, and that's its coding.
The idea here for the attack is for the sphere itself to drill through enemies who gib through its direct impact, and to explode against a non-gibbed dying enemy on impact.
During its travel, the sphere would spawn lightning attacks to nearby enemies (let's say 200/250 map units max).
And the explosion impact, instead of generating an explosion radius, would spawn a different lightning attack, one that would last an instant and generate more damage and an impact sprite at the end of the traceline, and its radius would be as long as vanilla thunderbolt.
Thing is, even though I have all the assets in place (models, sounds, sprites for the bfg sphere, big impact, and blast impact) I don't know how to properly code all of that.
I'm following these: http://www.insideqc.com/qctut/lesson-22.shtml http://www.insideqc.com/qctut/lesson-51.shtml
But I don't think I see anything related to "while bfgshot is in world" as a check to launch the nearby-lightning code.
 Think Fast
#1958 posted by Preach [77.99.55.146] on 2016/01/25 21:36:34
The trick is similar to the problem of the looping animation you had previously. You need to create a think function like
void() bfg_ball_think =
{
//insert lightning bolt code here
self.nextthink = time + 0.3; //how often lightning strikes
self.think = bfg_ball_think; //keep repeating
}
Then when you create the ball you need to add
missile.think = bfg_ball_think;
missile.nextthink = time + 0.2;
This gets you lightning shooting out as it flies, which is a good start.
 BFG Help Part2
#1959 posted by Daya [86.192.94.91] on 2016/01/27 00:28:10
Thanks again for Preach's help.
Now, for the lightning blast coming from the impact, the idea is to generate an impact sprite at the end of the lightning line generated. I know trace_endline has a role to this, and this is where the blast sprite function will be called, but I doubt "trace_endline = BFGBlast();" would work, as trace_endpos seems to be more attached to particle work.
Just for reference, here's what I wrote for the entire BFG (not including weapon animation, which aren't made yet): http://pastebin.com/E82MgGTy
 You'll Want To...
#1960 posted by Qmaster [70.195.73.153] on 2016/01/27 18:42:11
First remove the local variable org from within BFGBlast(), then add an argument so: BFGBlast(vector org) = {...
Then in your code where you do your head finding and t_damage, you can add just after that t_damage() a call BFGBlast(head.origin); to pass the location on to that spawn function for the explosion. In BFGBlast() you'll want to change it from self to be a newent so:
local entity newent;
newent = spawn(); //create new entity to become the blast
newent.origin = org; //set location to the ending of the lightning
newent.movetype = MOVETYPE_NONE;
newent.velocity = '0 0 0';
newent.touch = SUB_Null;
setmodel (newent, "progs/bfgblast.spr");
newent.solid = SOLID_NOT;
bfgexpl1 ();
sound (newent, CHAN_WEAPON, "weapons/bfgblast.wav", 1, ATTN_NORM);
 BFGBlast(vector Org) = {...
#1961 posted by Daya [90.18.250.248] on 2016/01/28 00:26:33
I don't get this part. This sure is not the start of a declaration (and isn't supposed to replace "void() BFG_Blast ="), as FTEQCC pointed out, but you said it's an argument... where should I put it? What should I put inside?
 The Argument...
#1962 posted by Qmaster [50.45.39.173] on 2016/01/28 02:25:13
The argument goes inside the parenthesis so:
void () BFGBlast becomes:
void (vector org) BFGBlast
OR
void BFGBlast (vector org)
either way you like at the start of your function.
The newent stuff is so you create a new entity for each lightning endpoint effect rather than keep moving only one otherwise if the main blast shot out at multiple targets you would only see the sprite effect on one of them.
 ...
#1963 posted by Qmaster [50.45.39.173] on 2016/01/28 02:32:09
Inside your BFG_Expl function is where you would call your BFGBlast function, rigt after T_damage. Whenyou put head.origin inthe parentheses: BFGBlast(head.origin); you are telling it to use the end position of your lightning as the value of "org" inside your BFGBlast function.
 DP Crash With The BFG
#1964 posted by Daya [90.18.123.191] on 2016/01/28 10:37:13
Thanks for your help QMaster. Now I'm testing it on Darkplaces, I get the gun, I fire it, the charging animation goes on, as just 0.1 second after the orb is fired, it crashes:
http://image.noelshack.com/fichiers/2016/04/1453973467-razenkrauft20160128102949-00.jpg
I also noticed it fired from off-center, somehow.
Here are the codes related to the BFG9500:
http://pastebin.com/5FdLg59C
 Another Thing, Related To Item Slots
#1965 posted by Daya [90.18.123.191] on 2016/01/28 11:23:41
The BFG's item slot is stored at the value of 16777216 (Infantry Gun is 128, Gatling Gun is 8388608), but when I pick it up, both shotguns disappear from my inventory and the original nailgun pops in it. Which value shouyld I put it? 16777216 is nowhere else to be found in defs.qc btw.
#1966 posted by Spirit [92.196.87.199] on 2016/01/28 11:38:22
Sounds like a integer overflow.
 Ok, So How Do I Fix It?
#1967 posted by Daya [90.18.123.191] on 2016/01/28 13:36:05
 ALLCAPS - Quake Maps In Unity?!
#1968 posted by khreathor [194.181.150.106] on 2016/01/28 15:40:21
Dude I can test shit for you!
 Hmm
#1969 posted by Qmaster [70.195.64.180] on 2016/01/28 16:34:51
Try changing the line in BFGBlast() from this:
bfgblast1();
To this:
newent.think = bfgblast1;
newent.nextthink = time + 0.100;
and also change effects from self to newent: newent.effects = newent.effects | EF_DIMLIGHT; //gives light to the end point
That might fix it, but I doubt it.
 It Didn't Change Anything, Sorry
#1970 posted by Daya [90.18.123.191] on 2016/01/28 17:00:47
One thing I noticed about the BFG firing off-center is that it seems to be arbitrarely firing at a fixed point, as seen here just before crashing:
http://image.noelshack.com/fichiers/2016/04/1453996496-razenkrauft20160128165312-00.jpg
And it's not the collision that crashes it: it seems like 0.05/0.1 second after firing the orb DP just crashes (I just tested firing against a wall: I could see the explosion sprite appearing just before crashing).
Maybe it has something to do with the lightning bolt continuous strikes checking for enemies?
Anyway, I won't be able to reply in here from now until Sunday, but feel freee to help on my case.
 Found It!
#1971 posted by Qmaster [70.195.64.180] on 2016/01/28 18:41:27
//head = head.chain; // cycle to next head (entity)
You commented out this line in bfgball think. What this does is cycle through the list of returned entities from findradius until the list is empty at which point head becomes null. Since you don't actually cycle the list, head never becomes null and the code is stuck in the while(head) loop forever...until the engine notices it and crashes to console.
 Whats The Most Complex Monster?
#1972 posted by Skiffy [175.138.117.8] on 2016/01/29 16:16:36
More a question of how far you can take standard quake that is. But what is / was the most complex monster behavior that has been done or attempted using standard quake? I do know that Arcane added some handy hint nodes if I remember correctly but has there been anything else that is of note when it comes to monster behaviors?
 Skiffy
#1973 posted by Kinn [86.136.122.222] on 2016/01/29 16:52:18
I think necros did some pretty badass shit in ne_ruins.
A-star pathfinding, some rather complex boss stuff...
#1974 posted by FifthElephant [178.111.101.82] on 2016/01/29 17:16:29
Surely bots have the most complex AI
#1975 posted by Skiffy [175.138.117.8] on 2016/01/29 18:00:56
ne_ruins was amazing indeed. Thanks for reminding me. I do wonder why nobody ever followed up using that as a base to make even more content. But indeed individual monster behaviors and reactions to the players and each other. How far was that taken in quake over the years is what I wonder.
 Bots
#1976 posted by ijed [186.9.129.9] on 2016/01/29 18:05:29
Are the most complex, but players complain when enemies have similar behaviours.
Bosses are complex, and the enemies of Nehara had a lot behind how they thought and moved.
Ultimately, ITS is probably the most complex, although that was a pure navigation system to some extent.
#1977 posted by necros [66.249.83.77] on 2016/01/29 21:40:44
I tried a couple of times to write a tutorial to let people integrate the ne_ruins navigation system, but it always ended up being really complicated and needing hooks into a few other places :(
 Ne_ruins
#1978 posted by Rick [75.65.153.192] on 2016/01/29 22:14:49
I only played ne_ruins once, back when it was first released, but I remember those zombies and I still think they are one of best Quake custom monsters ever.
 Necros Must Try Again! :)
#1979 posted by Skiffy [60.53.28.103] on 2016/01/30 04:51:16
 QMaster
#1980 posted by Daya [109.31.36.149] on 2016/01/31 21:38:39
I did what you said, and while the BFG orb doesn't crash, this is what happens:
*Picking up the BFG removes from the inventory all shotguns, puts in the nailgun, and all others inventory fuckery.
*The orb still fires at an arbitrary point in the map, probably a monster's waypoint beyond a wall.
*After firing, the upcoming weapon animation don't come up.
*When the orb collides with the world, only the particle explosion happen. No sound, no explosion sprite.
*When the orb collides with a monster, it changes direction.
*The proximity lightning which happens when the orb's active and an enemy is near it, it only happens when both the orb and the player are close to each other, and the lightning comes from the player.
*If the orb collides with an enemy and i'm too close to it, I die.
With all of this stuff happening, I'm just gonna post all of the qc files that mentions the BFG9500, since I just have absolutely no idea what's really going on, nor a single hint on how to fix it.
weapons.qc: http://pastebin.com/gW3P42yr
items.qc: http://pastebin.com/3u1ddwZM
defs.qc: http://pastebin.com/nV7xYWxH
player.qc: http://pastebin.com/DdyRggCm
 Item Erasure
#1981 posted by Preach [77.99.55.146] on 2016/01/31 22:56:53
As someone has already mentioned in the post above, your IT_BFG9500 value is too large, and that's what's removing the other items. Because you've got other weapons you're running out of space. One way out would be to use the slot from IT_SUPERHEALTH instead, it doesn't appear on the HUD when you set that, so you can safely remove it from the megahealth code.
You might also want to look at the mission pack 2 code, which uses an extra field called items2 to store more of the player inventory. There is extra support in the HUD for items2 if you use the mission pack command line switches as well.
 Wrong Direction Of Attack
#1982 posted by Preach [77.99.55.146] on 2016/01/31 23:14:21
The BFG shot goes in the wrong direction because of this line:
BFGShot(org, self.enemy.origin - self.origin);
It's important to know at this point which entity is self. It is the player. The problem is that the player does not have an enemy, because that's for the AI entities. So what's the default value if you don't have AI? The world!
This means that self.enemy.origin - self.origin is calculating the direction to the centre of the world. Instead you want to fire in the direction that the player is facing. When you do makevectors (self.v_angle); the direction the player faces is stored in a global called v_forward. So the fixes are:
1) Replace
makevectors (self.angles);
with
makevectors (self.v_angle);
2) Replace
BFGShot(org, self.enemy.origin - self.origin);
with
BFGShot(org, v_forward);
 One Thought At A Time
#1983 posted by Preach [77.99.55.146] on 2016/01/31 23:26:21
Now we come to
bfgsphere.nextthink = time + 0.1;
bfgsphere.think = bfgshot1;
self.nextthink = time + 0.1;
self.think = bfg_ball_think;
bfgsphere.nextthink = time + 5;
bfgsphere.think = SUB_Remove;
This segment of code is well intentioned but quite confused. The first thing to ask again is which entity is self? It is still the player! So the first step towards getting this working would be to change those from self to bfgsphere:
bfgsphere.nextthink = time + 0.1;
bfgsphere.think = bfgshot1;
bfgsphere.nextthink = time + 0.1;
bfgsphere.think = bfg_ball_think;
bfgsphere.nextthink = time + 5;
bfgsphere.think = SUB_Remove;
Now I ask what is stored in bfgsphere.think at the end of these 6 lines? It is SUB_Remove, because that last line overwrites the previous code which set it to bfg_ball_think, which itself overwrote bfgshot1.
I'm not going to post the solution yet, because this has tripped you up before Daya, and I wanna make sure the problem makes sense before we look at solving it. I fear in the past I've gone too fast over this issue which is why it's recurred...
 The Thinks Must Be In Decreasing Order, Correct?
#1984 posted by Daya [109.31.36.149] on 2016/02/01 10:56:15
This is what I did (and the other stuff too) while changing bfg_ball_think's think back to 0.3.
After all that, the projectile almost works: the orb animates properly, it fires at the direction I want it to fire, it produces the so-called blast after impact.
However the continuous lightning strikes from the orb still doesn't happen, colliding with the world without hitting an enemy don't spawn particles and says this: http://image.noelshack.com/fichiers/2016/05/1454319929-razenkrauft20160201104422-00.jpg , colliding with an enemy that gets gibbed still sends the orb to another direction, none of the explosion sprites (both orb impact and blast) show-up, when the blast happens the particle effect that should appear on the enemy appears instead at the origin point of the blast, and when I'm too close to the impact I get targeted by the blast, even though the code should avoid that.
Here's the code in weapons.qc once again, as I've added some more stuff in addition to yours: http://pastebin.com/EAV4PayU
#1985 posted by Spike [86.191.134.58] on 2016/02/01 11:40:44
local entity bfgexpl;
bfgexpl.movetype = MOVETYPE_NONE;
that's an assignment to world.
remember that world is equivelent to null or nothing (and that locals default to nothing, or at least whatever 0 means), thus assignments to its fields are considered a bug - and this case is certainly no exception.
 Did Some Modifications
#1986 posted by Daya [109.31.36.149] on 2016/02/01 14:11:15
Notably for both touch and explosion functions, where I looked at the rocket launcher's touch and explosion functions.
http://pastebin.com/KDRyZmG3
The explosion itself now spawns the particles (and the error messages don't show up this time), but the sprites still don't show up.
 Only One Think
#1987 posted by Preach [77.99.55.146] on 2016/02/01 21:27:27
No, you can only have one think. Just one. When you set the second think, it replaces the first one. The first one will never happen. There is no queue. You can only have one think. The only think which is coming out of your code is SUB_Remove because the others have been replaced before they have a chance to happen. An entity can only have one think, and it is always going to be the one you assigned most recently. Only one.
 SUB_
#1988 posted by ijed [200.73.66.2] on 2016/02/01 22:02:13
One think to rule them, one think to find them,
one think to bring them and in the dark places bind them.
 So With That
#1989 posted by Daya [109.31.36.149] on 2016/02/01 22:52:12
I removed the thinks except for bfgshot1 which commands the orb's animation. I tried to call bfg_ball_think directly on each frame of the orb's sprite but still no dice.
The reason I'm not hiring a coder is because time zones are a complete bitch and I want to have complete control on the mod.
 Timing
#1990 posted by Preach [77.99.55.146] on 2016/02/01 23:04:59
When you changed it to only call bfgshot1, did you also change it so that the only nextthink line is:
bfgsphere.nextthink = time + 0.1;
If you left the line
bfgsphere.nextthink = time + 5;
in then it'll only kick in 5 seconds later, and it'll collide with a wall first!
 The Only Remaining Next.think And Think Fork Remaining Is
#1991 posted by Daya [109.31.36.149] on 2016/02/02 00:02:42
bfgsphere.nextthink = time + 0.1;
bfgsphere.think = bfgshot1;
But by replacing some code in bfg_ball_think:
org = self.origin + '0 0 16';
head = findradius(self.origin, 250);
The continuous lightning now works on the enemies, but myself as well.
Normally "if(head != self)" should avoid that, but it gets ignored, somehow.
(Also the sprites still don't spawn, and the blast sound effect happens at the orb's impact, not at the enemies targeted, as wanted)
 Issues With Bfg_ball_think
#1992 posted by Preach [77.99.55.146] on 2016/02/04 00:49:04
So there's a bit of explanation to do with the magic entity self which may explain why this code didn't work:
local entity lightcont;
org = lightcont.origin + '0 0 16';
but your modification did, and why if(self != head) is failing to protect you.
self is a variable which stores an entity, but which entity it stores changes as the engine checks different things. When the player is launching attacks, then self is the player. But when other entities are running their think functions, then they become the new self. So we need to always remember who is calling a function to reason about self.
During bfg_ball_think what is self? The ball of death, not the player! Aside: how about lightcont? Well, you never assign anything to it in your function, so it is always equal to the world entity. This is why that wasn't working before you modified it.
Anyway, back to self. The problem is that we want to get back to the player who fired it, but if the ball is self then where is the player? Luckily, all the way back when we created the ball we had a line
bfgsphere.owner = self;
At that time self was the player and bfgsphere was the ball, so now that self is the ball, self.owner is the player we stored! So we change the check to
if(head != self.owner)
and the player will be unharmed.
Can you post a current BFG_Blast and related functions? This had issues in the old incarnation but you may have fixed or changed them...
 This Is All Rather Interesting!
#1993 posted by Qmaster [70.195.72.121] on 2016/02/04 04:15:21
Back to the IT_BFG9500 issue with messing up the inventory. The way the IT_'s work is by turning bit values on or off (0 or 1) in the single float variable self.items.
So a player with no items has a self.items of 00000000000000000000000 in binary (23 slots {mantissa for you super nerds} because of the way quake stores memory, the other bits are for exponent and a bit for positive/negative) QuakeC sees it as a float of 0 or whatever number the IT_'s add to unless you use the bitwise operator & to see if bit IT_something is turned on.
If you have the axe, shotgun and supershotgun self.items, in binary is 00010000000000011000000 and float is 4099.
This is the conversion of the number 4099 into binary. 4099 = 4096 + 1 + 2 (axe + shotgun + dbshotgun). If you subtract the supershotgun from self.items (4099 - 2) then the binary of self.items is 00010000000000001000000
We turned off one bit. The problem is that 16777216 needs 25 bits to store it. It is too large. So it causes your bits to get all wrong and shifted when you try to add it using the bitwise | operator, hence the inventory loses stuff and gains stuff. I wouldn't even use 8388608 either since it needs 24 bits. I ran into that same problem. If you use 65536 instead, it should work fine, so long as you remove the calls that the megahealth uses in items.qc
 Also,
#1994 posted by Qmaster [70.195.72.121] on 2016/02/04 04:24:07
Note that by using the set of all integer values that equal powers of 2, the sum of any n values is inherently unique from any other sum of n values.
 Two Things Fixed At Once
#1995 posted by Daya [109.31.36.149] on 2016/02/04 10:10:38
First, the continuous lightning now works properly (even though it should spawn at the center of the sphere) :
http://image.noelshack.com/fichiers/2016/05/1454576771-schlossherr20160204095929-00.jpg
And the BFG doesn't mess with the inventory (I think that was because I assignated it with the Mega Health slot, as previously stated by Preach):
http://image.noelshack.com/fichiers/2016/05/1454576771-schlossherr20160204100351-00.jpg
I'm really happy it functions properly now. All there is to fix now is spawning the explosion and blast sprites properly and make the lightning start from the center of the sphere.
 Forgot To Put It In The Code
#1996 posted by Daya [109.31.36.149] on 2016/02/04 10:11:22
 Daya
#1997 posted by FifthElephant [178.105.170.54] on 2016/02/04 11:41:27
Good work man :)
 Lightning Start Pos
#1998 posted by Qmaster [70.195.74.210] on 2016/02/04 16:08:43
Maybe this line should be changed:
org = self.origin + '0 0 16';
To: org = self.origin;
 That Did It!
#1999 posted by Daya [109.31.36.149] on 2016/02/04 18:20:05
One last thing I forgot to mention before, aside from the sprites problem, how do I make the sphere not change direction when it hits a monster that gets gibbed?
 Pass Thru Bullets
#2000 posted by Qmaster [70.195.74.210] on 2016/02/05 03:27:22
You should check out the nail piercer code from the AD mod just release, it should help you to see how the nails think/touch when the player has the piercer effect on.
 Where Is It Exactly?
#2001 posted by Daya [109.31.36.149] on 2016/02/05 19:11:45
I found nailpiercer but only for the powerup duration, not the actual code itself. W_FireSpikes only has codes for firing offsets and nailguns switching.
#2002 posted by necros [173.199.65.22] on 2016/02/05 19:47:44
dunno about that code, but the easiest way to me would be to create a new .entity field and store .owner there instead.
then, every time it hits something and you go to do your damage, temporarily swap the entity back into .owner before you call t_damage. then set .owner to be the monster you just hit, making it non solid to the nail.
 Yes
#2003 posted by ijed [186.9.134.104] on 2016/02/05 22:07:01
I think that's how Supa handled it in the RMQ code. You need to add it to each thing you want to pass through - grenades probably and rockets maybe.
Also a flag for breakables - this should happen with stained glass but not crumbling bricks for example.
We also made nails go through zombies, but not gib them. Which was fun, but also pretty pointless, with hindsight.
#2004 posted by necros [174.95.107.3] on 2016/02/06 01:45:10
i did that for the fast zombies in ruins! it lets you kill dozens with well placed quad shotgun blasts. :D
i did limit shells and nails to only penetrate once. and nails turn ballistic after hitting the first zombie.
 Items2
#2005 posted by Teknoskillz [73.142.34.180] on 2016/02/06 02:14:28
Someone mentioned the items2 field, which can be used but carefully, as the values you place into it reflect runes showing up in the hud.
[ Also it will have to be floated in a safe place , IE: .float items2; ]
32 = Resist
64 = Strength
128 = Haste
256 = Regen
I believe values < 32 and above 256 up to the max limit would be ok to store some new stuff, but I thought I remembered someone saying something weird happens to the hud if you do that, not sure...
 Bfg
#2006 posted by Teknoskillz [73.142.34.180] on 2016/02/06 02:21:57
@Daya
Note you could also give that bfg ball a purple glow that may look pretty good since its purple already.
When it spawns, make its .effects field = EF_RED | EF_BLUE;
By the looks you are using Darkplaces engine is why I suggest it, if not it wont work.
Also looks like your beams from the orb pass through the targets they zap which is ok, but you could also pickup the end of the traceline where it contacts their hitbox using trace_endpos, then use that as the end point for the beam when you call the effect. I have done that with the Thunderbolt and spawned spark effects there. Not sure if you are already doing that, I didnt look at your code yet, but thought I would mention it.
 Thanks Teknoskillz
#2007 posted by Daya [109.31.36.149] on 2016/02/06 09:59:34
But right now I'd like to focus on that sprites spawning problem and I can't find a damn solution about it. It shouldn't be that hard!
Speaking of which, how was Quoth able to make the explosion particles blue? I wanted to do that but it only made the vanilla explosion particles. And that EXPLOSION2 alternative make the impact look like water splashes.
And I plan for this mod to be playable on most clients (quakespasm, fitzquake and DP for starters) so making DP-only code wouldn't be a good idea.
 The Endpoint Is Near?
#2008 posted by Preach [77.99.55.146] on 2016/02/06 17:20:20
In BFG_Blast, it's important to remember that self is still the projectile, not the extra sprite you've spawned at the end of the lightning. This has an impact in two places
1) Where you have the following code...
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
...it is making sparks at the origin of self, i.e. the projectile, not the endpoint of the lightning. Change this to use org, the vector that you pass to the function.
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
2) The following line of code is very subtle in its effect:
bfgblast1();
This is actually triggering a think function on self, when you want it to trigger on the newent you've created. Try something like
newent.nextthink = time + 0.01;
newent.think = bfgblast1;
This should improve things.
Quoth uses TE_EXPLOSION2 for the plasma effects, but where you use colour 246 we use 35. Bear in mind that there is a particle limit, and firing several explosions at the same time may well exceed it (you can also hit it if you gib enough monsters in a single second). An alternative would be to go down the lines of a canned mdl animation in the vein of
https://tomeofpreach.wordpress.com/2012/11/21/embers/
Obviously for the particles to be appropriate for a BFG it would need more than just a palette swap, but let me know if that would interest you...
 The Explosion Particle For The Blast Now Appears
#2009 posted by Daya [109.31.36.149] on 2016/02/06 18:49:48
And the Blast sprites appears now, thanks to "setmodel (newent, "progs/bfgblst.spr");" (it was self instead of newent). Thing is, they appear at the target's foot. This maybe points to the origin. Another thing is that when the blast sprite shows up, it skips the first frame and plays it at the end of the animation. Does it has something to do with "newent.nextthink = time + 0.01;"?
The explosion sprite itself still doesn't appear though. I tried
self.nextthink = time + 0.01;
self.think = bfgexpl1;
Similarly to what you suggested for BFG_Blast, but no dice (tried both with self and bfgexpl).
 Sprite Animation
#2010 posted by Teknoskillz [73.142.34.180] on 2016/02/06 21:25:58
Fimg comes in handy working with Sprites [ http://www.insideqc.com/frikbot/projects.php ]
But the issue you have might be because when the ent spawns, the frame by default is 0. So try starting it at frame 1 in the macro code. Otherwise open it up in Fimg, there could be an extra frame in there or the sprite file could be corrupted.
 The Sprite File Wasn't Corrupted Or Anything
#2011 posted by Daya [109.31.36.149] on 2016/02/06 21:45:20
But I changed the animation cycle so that it starts at the last frame and cycles back to the beginning:
void() bfgblast1 = [4, bfgblast2] {};
void() bfgblast2 = [0, bfgblast3] {};
void() bfgblast3 = [1, bfgblast4] {};
void() bfgblast4 = [2, bfgblast5] {};
void() bfgblast5 = [3, SUB_Remove] {};
And the sprite animates properly now. Kind of wierd since the vanilla explosion sprite doesn't have that problem.
 Again, Why Would The Blast Sprite Show Up Properly But Not The
#2012 posted by Daya [109.31.36.149] on 2016/02/07 00:57:40
explosion one? I can't find any issues.
 Experiment
#2013 posted by Preach [77.99.55.146] on 2016/02/07 01:07:25
Reset your code to start the frames from 0, then try swapping the filenames, renaming A to B and B to A. If it's still the one at the centre of the explosion which is skipping the first frame then we know the problem is in the code. If it starts being the the sprite on the blasts which is out-of-order then we know it's a sprite file issue.
#2014 posted by Shambler [2.99.180.113] on 2016/02/07 22:56:26
A Quake C Exercise [EDIT]
Posted by Teknoskillz [73.142.34.180] on 2016/02/07 22:38:53
We seem to have alot of good QC coders here, so wanted to see if any are up to collaborating on a new modification for the gibs, where (and heres where its kinda gross :o) ) we give the gibs a .touch field and check for an impact against a solid where we look for vlen (self.velocity) > a certain value, and if its moving very fast and hits say the bsp, we do 1 of 3 things:
1) Make it stick partially in the wall or the ceiling. (sort of like the nails stick in walls mod)
(I believe I have played a Doom mod out there that does this)
2) Same as 1, but make it slide down and or maybe fall off the wall with a seperate think.
3) Create a "splat" effect , either using a new sprite which is sorta a flattened image of the original gib, or perhaps use a decal?
I have no knowledge of decals, not really sure if its possible to use QC for that, as it may be an engine only effect.
 Some Answers
#2015 posted by Preach [77.99.55.146] on 2016/02/08 00:01:33
1) Make it stick partially in the wall or the ceiling. (sort of like the nails stick in walls mod)
This is easy. Make this the .touch function of a gib
void() gib_touch =
{
if(vlen(self.velocity) > 300 && other = world)
{
self.velocity = '0 0 0';
self.movetype = MOVETYPE_NONE;
self.avelocity = '0 0 0'
}
}
2) Same as 1, but make it slide down and or maybe fall off the wall with a seperate think.
This will be a bit harder, and I don't think the request is fully specified yet. For example, what happens if the gib hits a ceiling? How about angled surfaces? Sloped up or down?
Regardless of the answers to these questions, there are some concerns which always apply. There's no simple way of determining the facing of the surface we collided with. We could try and traceline backwards but this may be inaccurate in corners. There's also a bug with MOVETYPE_BOUNCE entities moving down slopes just get stuck.
However, in the simple case where we have determined that we've hit a proper wall, one which is not sloped but perfectly vertical, you could probably simulate sliding down the wall quite well by setting self.velocity = '0 0 0' and self.gravity = 0.4.
3) Create a "splat" effect , either using a new sprite which is sorta a flattened image of the original gib, or perhaps use a decal?
Gonna pass on this, there's no actual decal support in normal engines, and there are loads of pitfalls in using sprites.
 Preach
#2016 posted by necros [172.98.67.80] on 2016/02/08 03:05:12
if(vlen(self.velocity) > 300 && other = world)
^_^;
 Touch Field
#2017 posted by Teknoskillz [73.142.34.180] on 2016/02/08 07:53:46
One day I decided to peek at trace_plane_normal while in a touch field..and like I thought, it was returning the correct value corresponding to the type of plane it hit, with respect to world. I was using DP of course, but according to Lord Havocs response, it seems like all the other engines would replicate this. Of course give it a try and see.
So if that turns out to be true, then could we not use this to determine the angle we need to align the gib? Im guessing it only makes sense to do this if its a perfectly straight wall or ceiling, but I suppose we could do sloping cielings without a problem. Sloping floors not so important, as that would boil down to more of a rolling effect.
Yes vlen > 300 and touching world is a start. However I might reinforce that code to also cover non world ents which also have a bsp solid, such as exploboxes, doors and I suppose plats that are doors...and I guess buttons.
 Heres A Start ...
#2018 posted by Teknoskillz [73.142.34.180] on 2016/02/08 08:14:28
http://collabedit.com/phw6e
Neat site I think will let us collaborate code.
Would vectoangles of the normal set the angles on the gib correctly?
 Er, Yeah
#2019 posted by Preach [77.99.55.146] on 2016/02/08 08:15:26
As necros kinda pointed out, that should read
if(vlen(self.velocity) > 300 && other == world)
You don't want to use things other than the world, because those things might move. This code doesn't attach the gib to a moving object, it just stops it from moving. You might end up with a gib suspended in the air.
 Moving BSP Ents
#2020 posted by Teknoskillz [73.142.34.180] on 2016/02/08 08:24:02
True, however I suppose we could look for that case where its already a movetype 0, and is contacting a bsp != world...or like I have seen in some other code in my travels, somoene had marked the origin it stuck to and used setorigin I believe in the doors think to find it. Maybe more complex, but for now I guess we can think about it for later.
 So Where To Begin?
#2021 posted by Skiffy [219.92.193.192] on 2016/02/08 13:35:22
So what compiler to use if I want to start wandering into Quake coding?
FrikQCC 2.0 I read was one of the later versions correct? Other than reading all 2000 posts in this thread which will be a good start I guess.. any more focused coding site for quake? :)
Thanks in advance!
 At The Risk Of Being Biased...
#2022 posted by Spike [165.120.199.187] on 2016/02/08 15:40:38
if you're on windows, fteqccgui.
tell it to debug with fteqw and you get breakpoints and other nice debugging stuff.
http://triptohell.info/moodles/win32/fteqccgui.exe
place in your quake directory and set up a file association for .src files so you can easily start/update it etc. making lots and lots of copies also works, but yuck.
imho frikqcc is kinda obsolete now, but there are still people using it, it was good for its time.
if you prefer commandlines/alternatives, there's also (non-gui) fteqcc, gmqcc, or qfcc.
gmqcc is used by xonotic, whereas qfcc is kinda dead and unused.
the bigger issue is which mod you use as a base. that mod may depend upon specific features of the qcc it was written for.
if you're targetting either fteqw or dp, these engines have their own FOOextensions.qc files so that you can quickly get started with their various extensions. note that the inclusion of either of these extension def files does not automatically rule out compatibility with other engines, but you may still find you end up using extensions without realising it, resulting in issues with engines that don't support them.
 FTEQCC
#2023 posted by Qmaster [70.195.73.11] on 2016/02/08 18:34:05
Also has support for arrays and other cool stuff that isn't available in standard qcc compilers. I used proqcc.exe for a while, but FTE is the best. It even gives you a warning if you have added variables up too high in your defs.qc file. You can double click errors to open the file right at the error line. It's great.
 In And Out Of Water Monsters?
#2024 posted by Skiffy [210.195.226.108] on 2016/02/10 14:16:50
Is this possible? A monster that can swim and lurk in the water but also jump out and follow you on land if you get too close? I would love a big sort of lurker type water monster that stays near the surface and mainly attacks from the water or under water when you are spotted underneath but if you are on the shore it could jump out and maul you / run after you. I find Quake's water to be very empty except for the rot fish :P
 Of Course
#2025 posted by Kinn [86.154.183.77] on 2016/02/10 14:22:42
some logic to detect if enemy is on land and jump out if close to surface, and then just take off the swim flag, should do it
Jumping in would be similar.
Obviously the devil will be in the details
 Skiffy
#2026 posted by FifthElephant [86.4.213.148] on 2016/02/10 16:05:11
 Hmmm...
#2027 posted by Qmaster [70.195.68.229] on 2016/02/10 18:45:29
A fiend with a fish tail would be cool. It could swipe at you from the water, then jump out when you back away and behave like a normal fiend on land. Then when he falls back in the water he could swim. Make him tougher than normal fiends, color him different and put gills on his skin, and make a good environment sort of like e4m1 with lots of water (but of course medieval). I like it. :). Could also do a variant that does the TEelzap if you get too close in the water.
 Harpio
#2028 posted by madfox [84.84.178.104] on 2016/02/10 21:37:10
I tried once with Harpio, a kind of waterdragon.
Hard to get the coding right, as I needed two kinds of attacks, on land and in water. In the end it was easier to get them in water then back out again.
view
#2029 posted by metlslime [159.153.4.50] on 2016/02/10 21:55:21
i wonder if you'd need something like trigger_monsterjump to get the guy to come out of / go into the water.
#2030 posted by necros [172.98.67.84] on 2016/02/10 23:14:46
you could use a version of the player get out of water code.
 Code
#2031 posted by madfox [84.84.178.104] on 2016/02/11 01:30:47
It is something in the qc code.
I made a land type(harpo) and a water type(harpi)that change with a void() harpo_to_harpi; and a void() harpi_to_harpo;.
The land to water function goes right:
void() h_jive1 =[ $djive1, h_jive2 ] {harpi_to_harpo();};
but for some reason the other one doesn't return the call:
void() h_mour1 =[ $mour1, h_mour2 ] {harpo_to_harpi();};.
Maybe a monster_jump would help but I think it will stay swimming on dry ground.
I looked at the water code and how the positions are defined, but I couldn't get a rig on it.
 Gibs Stuck On Wall
#2032 posted by Teknoskillz [73.142.34.180] on 2016/02/11 01:50:40
Tried the code Preach and I collaborated on a little, seems to be working, heres a screenshot.
http://i.imgur.com/T8feCWg.jpg
I guess a skull or head model has a low chance of sticking in a wall before it breaks up, so will have to code in that case.
Im using DP so I was able to assign the gibs a bloodtrail modelflag, even though these dont have any. The blood dont last very long but I suppose thats the engine setting kicking in.
Would be neater if they had a flattened area contacting the wall , so that it might look more realistic. I suppose maybe what could be done is the model have more scenes made into it that flatten it different percents and at some random angles....then we align it to the wall with that angle...?
 Hm
#2033 posted by necros [172.98.67.84] on 2016/02/11 01:55:48
that looks worse than it sounded like it would. :(
at least don't make skulls stick, that's silly. and you need to put blood decals or something to make it blend into the wall more or something.
 Fiend With Tail... Kinda Yea.
#2034 posted by Skiffy [219.92.52.161] on 2016/02/11 02:24:17
The water dragon / fiend with tail indeed is the type of thing. I find water so empty in the game when it comes to enemies. But then again your ability to stay under water is vague and short on time. Still I like the idea of some more things to worry about besides rotfish and air when traversing the depths of quakes rusty waters.
#2035 posted by FifthElephant [178.100.118.177] on 2016/02/11 02:31:01
The expansion had electric eels. Scrags look OK underwater. Zombies don't need to breathe ;)
#2036 posted by Spike [86.180.169.148] on 2016/02/11 05:45:34
spawns... at least underwater you won't get quite so annoyed at them.
if you're jumping out of water, you need to move at least far enough to get your monster's bbox to leave the water and then progress past any ledge above the water surface too. and after all of this, it then needs to also go forwards if it somehow managed to avoid impacting the wall and losing its sideways momentum...
which is why the quake player keeps trying to move forwards while waterjumping, regardless of what the player wants or really anything else. the player must a: be next to the side. b: far enough up that a tracebox can go up, leave the water, move sideways slightly, then move down again and hit ground that is actually viable (ie: somewhat flat). c: then the upwards velocity is set, a teleport_time flag is set, the player looses control of their sideways velocity. d: that upwards velocity takes the player out of the water, the forced sideways velocity that ignores walls takes the player sideways once he's far enough out of the water, and when the player gets control of their velocity again then they've successfully left the water.
because, quite frankly, teleporting out of the water is stupid.
if its a monster, be careful about FL_PARTIALGROUND, if your monster didn't get fully onto land, the monster will be able to casually walk over the ledge and fall straight back into the water.
the problem with just casually hopping out of the water like the player does it is that it lacks presence or menace, its just another monster to kill. you might as well just teleport them in if you don't have that.
some sound effects or cool animations might do the job.
slowing the transition down so the player gets a chance to panic at 10 of them getting out of the water while he's got no ammo. that's the way to do it.
alternatively you could have fish that move fairly fast and spit, which means they'll keep sniping the player while being impossible to see/shoot thanks to the opaque water surface.
the player then has the option of either trying to ignore/dodge said spit/whatever, or jump in and get eaten by the fishies.
 Underwater Monsters
#2037 posted by Teknoskillz [73.142.34.180] on 2016/02/11 07:58:18
There is def a lack of them, the Eels in Rogue were neat. As for spawns, you could put them inside a secret door of sorts that they exit out of, on the walls or the floor, or a tunnel that leads inside the wall to their home.
I always thought movetype_fly was better for swimming monsters...simulates no gravity. flymissile will make em bounce off the wall for more accurate physics with the right velocity calcs. Just have to make sure you dont break the surface and are in empty air. Air pockets could pose a challenge tho...
 Can Models Change Size?
#2038 posted by Shamblernaut [121.45.236.153] on 2016/02/11 10:24:14
because a spawn that is really thin and wide on the ceiling, and then drips down into a blob on the ground would be cool.
 Monster Size
#2039 posted by Qmaster [70.195.68.37] on 2016/02/11 13:51:47
No...all monsters are one of two sizes. 32x32x56 or 64x64x88. If you assign a size other than these the engine will round it to the nearest size. This is because of the way the engine handles collisions. Every level has a hull0 and a hull1 for the two sizes above. When a level gets compiled the compiler creates 3 versions of the map geometry, one for what you see and shoot, one for what you and other hull0 sized creatures collide with, and 1 for larger monsters. The hulls are all shrunk in from the walls by half the width of the bounding box so that collision only happens as if every solid object were only a point.
You can, though, make it visually different sized, but the collisions will stay the same.
 Actually
#2040 posted by Kinn [86.154.183.77] on 2016/02/11 13:59:32
The size with respect to the level collision can be of 3 values; the two mentioned by Qmaster, or point size.
However, for the purposes of entity/entity collision, the bbox will use its actual size, not the hull-rounded size.
 WOW Why?
#2041 posted by Skiffy [1.32.21.125] on 2016/02/11 15:00:58
ok that is a rather gimped limitation wow. no way to hack around that I guess without changing the engine itself?
How the heck do you do large boss monsters then?
 You Can Do It Like Armagon
#2042 posted by Daya [109.31.36.149] on 2016/02/11 15:13:12
e.g Have a main model (the legs) and have a secondary model "attached" to it (the upper body)
 Skiffy
#2043 posted by Kinn [86.154.183.77] on 2016/02/11 15:38:06
I may be imagining things, but a very clever solution was used by necros in Altar of Storms (necros please correct me if I'm wrong) that went something like this:
1) have a fuckoff huge monster in big arena-like environment
2) build a dummy small version of the arena environment somewhere player can't reach. In this small environment there's a normal-size version of the big monster (let's say it's shambler-hull-sized) The size of this small environment relative to the shambler hull should be in proportion to the size of the big environment relative to the intended big monster size.
3) The small monster moves around the small dummy environment fighting a dummy player entity (whose position is updated based on the real player's position. Similarly, the big monster in the real environment gets its position set based on what the small monster is doing.
Hope that makes sense. The concept is simple really, it's just about setting up master/slave entities at different scales to each other.
 Also Skiffy
#2044 posted by Kinn [86.154.183.77] on 2016/02/11 15:48:33
the way Quake does it is for performance reasons - back in 1996 it was a big deal to make collision as cheap as possible so reducing all entity/world tests to point tests was desirable.
Of course, expanding the bsp tree on the fly was too expensive so they settled on using just 3 pre-baked versions of the tree, with the tradeoff that you only get 3 sizes of entity wrt the world.
 Thanks For The Info Everyone
#2045 posted by Skiffy [1.32.21.125] on 2016/02/11 16:11:35
That concept sounds like a wicked hack... and it makes sense too. If he did indeed do that then its rather amazing.
Its nice to have some quakeC coder brains to pick and ask all these questions.
 Collisions
#2046 posted by Teknoskillz [73.142.34.180] on 2016/02/11 17:27:20
I thought the 3 hulls were point , player and shambler. Anhyow, why could not the hull limit versus world/ bsp map entity be overcome by using code like this:
(This was originally Lord Havocs Idea)
float (vector loc, entity subj) Inbounds =
{
if (loc_x <= subj.absmin_x
|| loc_y <= subj.absmin_y
|| loc_z <= subj.absmin_z
|| loc_x >= subj.absmax_x
|| loc_y >= subj.absmax_y
|| loc_z >= subj.absmax_z)
return (0);
else
return (1);
};
Where subj would be the world entity, and the loc would be a spot on the hitbox. I believe you could use the ents absmin or absmax as loc and still get it to work, or to be sure, run it on the other 2 corners of the hitbox as well.
Theres also the stock ID function EntitiesTouching ()
Which is for the doors, and since they are models with their origins hard coded, with respect to world, they use mins / maxs, however I have modified it so you can check absmax and absmin, pretty easily by defining an operating mode:
float (float mode, entity e1, entity e2) EntitiesTouching =
{
// Cobalt mode float - modifies to cover absmin/absmax, else do normal mins/maxs
local vector low1, high1, low2, high2;
low1 = e1.mins;
high1 = e1.maxs;
low2 = e2.mins;
high2 = e2.maxs;
if (mode)
{
low1 = e1.absmin;
high1 = e1.absmax;
low2 = e2.absmin;
high2 = e2.absmax;
}
if (low1_x > high2_x)
return FALSE;
if (low1_y > high2_y)
return FALSE;
if (low1_z > high2_z)
return FALSE;
if (high1_x < e2.mins_x)
return FALSE;
if (high1_y < e2.mins_y)
return FALSE;
if (high1_z < e2.mins_z)
return FALSE;
return TRUE;
};
 Lord Havoc's
#2047 posted by Qmaster [70.195.68.37] on 2016/02/11 18:25:52
Darkplaces allows this: mod_q1bsp_polygoncollisions 1
But it is a bit buggy, the player can get stuck sometimes on any vertical surface such as walls. I was using it for a while for my Citadel mod to do crouching and prone and to size enemies better but it was just too unpredictable. Thats why I had to chamge it to use Unity, sadly.
 3 Hulls
#2048 posted by Qmaster [70.195.68.37] on 2016/02/11 18:30:06
You could, I suppose, use point for your monster size, but it would look wierd whenever it ghosted halfway through walls. And of course there's the issue of you being able hit it with your point sized bullets.
#2049 posted by khreathor [194.181.150.106] on 2016/02/11 18:32:01
Thats why I had to chamge it to use Unity.
What do you mean by Unity?
 Cough Cough Different Engine
#2050 posted by Qmaster [70.195.68.37] on 2016/02/11 18:38:02
 Qmaster
#2051 posted by khreathor [194.181.150.106] on 2016/02/11 18:52:00
Any link to your project?
 Kind Of Off-topic But
#2052 posted by Daya [109.31.36.149] on 2016/02/11 19:36:17
Is Unity good enough as an engine to make a Q1-like that looks similar to UT99/the Half Life HD pack?
 Daya
#2053 posted by Kinn [86.154.183.77] on 2016/02/11 19:54:46
yes
 Short Answer Is Yes
#2054 posted by khreathor [194.181.150.106] on 2016/02/11 20:17:00
I'm currently "preparing for"/designing a game inspired by Blade Runner with Quake-like graphics.
Most problematic is non skeletal animation and making game modable.
First problem you can solve with blendshape animation, or by writing your own animation system (just loading vertices states).
Second problem is more challenging... Easiest way is to let people create and script maps in Unity and export them as Asset Bundle, then load them in your game. This delivers few problems:
1) You have to open part of your source so people can use and modify logic - for example adding some functionality to existing door script;
2) C# Scripts must be compiled into assembly - not a big problem, but pain in the ass when you test stuff;
3) If you give people access to C#, you have no control what is executed in your game - I can create a map that will delete or acquire some important data from your hard drive.
But... few days ago I have discovered nice Lua integration for Unity and .Net in overall. It's opensource, easy to use etc.
So instead of C# we can use Lua scripts = much easier editing and testing, easier to avoid malware behavior.
For mapping you can use free version of Pro Builder: https://www.youtube.com/watch?v=0yB_Q7yECwk
So all your mod tools stay free.
Rest is piece of cake...
 I Planned On Using Skeleton Animation For Smoother Animations
#2055 posted by Daya [109.31.36.149] on 2016/02/11 21:01:10
As well as ragdolls in tandems with actual death animation for avoiding flat lifeless bodies hanging on ledges and whatnots (and also for doing high-impact on deaths a bit more convincing). Half Life did skeletal animations on low-poly models right and Metroid Prime did the animation/ragdoll tandem well, so it's possible.
It's also a relief modding is possible, it's one of the thing I was looking forward when developping my game.
And as long as that Pro-Builder has a grid and surface texturing I'm fine.
 Kinn
#2056 posted by necros [66.249.83.80] on 2016/02/11 21:53:38
That's a cool idea, but not how I do huge monsters.
I make 1 bmodel that becomes the clip brush for huge monsters, I basically pad the walls out with it.
Then at level start it is non-solid.
Everytime the huge monster moves, it sets it's bbox to shambler size, makes the clip model solid and then walks.
 Necros
#2057 posted by Kinn [86.154.183.77] on 2016/02/11 22:41:51
Aha! So I was kinda imagining things :) Or, I half-remembered it and tried to fill in the blanks myself or something.
I guess the problem with the method I mentioned is that it could get messy when you have more than just the boss and the player moving around in the environment - you need a master/slave setup for every entity that the boss's movement needs to know about.
 Citadel
#2058 posted by Qmaster [70.195.68.37] on 2016/02/12 01:50:32
 Here Thar Be Dragons
#2059 posted by ijed [200.73.66.2] on 2016/02/12 18:11:32
Patrick Martin had a special trick for large BBOXs in his Drake mod and the Dragons patch.
http://www.quakewiki.net/quake-1/mods/dragons/
I love his code - so many interesting and creative monster improvements.
 Fteqcc.exe
#2060 posted by necros [174.95.107.3] on 2016/02/14 04:32:28
Any way to disable this: warning: Model progs/clutter/bookclos.mdl was used but not precached
I'm using Preach's wrapper that magically fixes this problem, but now fteqcc yells at me for being clever. :(
#2061 posted by Spike [86.180.169.148] on 2016/02/14 05:04:10
you mean other than this?
precache_model("progs/clutter/bookclos.mdl");
Note that you can also use this, for instance:
precache_model((self.mdl = "progs/clutter/bookclos.mdl"));
yup, assignments in function calls are evil, but it will do the right thing, and only need the mdl named once (you could also make some macro, eg preset_mdl).
And of course, if you just want to hit it with a sledgehammer instead of playing whackamole:
#pragma warning disable F210
note that doing so will of course hide any other instances (which may be more significant).
you can use this method to disable any warning that fteqcc gives a code for, but you run the risk of shooting yourself in the foot if you just disable everything, so use with caution.
 Thanks
#2062 posted by necros [174.95.107.3] on 2016/02/14 05:13:18
doesn't seem to work though? where do I put the #pragma line? I tried in defs.qc (the first file in progs.src) and also in one of the files where I get this warning, but neither had any effect. I also tried #pragma warning off F210 from here: http://fte.triptohell.info/wiki/index.php?title=Precompiler_definitions&action=edit
btw, preach's trick is thus:
void(entity e, string m) setmodel_builtin = #3;
//preach's wrapper function for setmodel!
void(entity e, string m) setmodel =
{
if(framecount == 0)
{
if(m != "")
precache_model(m);
}
setmodel_builtin(e, m);
};
which neatly stops you from ever having the problem!
 Ahhh Pardon Me
#2063 posted by necros [174.95.107.3] on 2016/02/14 05:15:26
that mod folder had an ancient copy of fteqcc. :P
all good now, I think.. thanks!
#2064 posted by necros [174.95.107.3] on 2016/02/14 05:18:54
oh... btw, warning F304: unary-not applies to non-unary expression
I liked the warning in the old version where it just told you warning: You may wish to add brackets after that ! operator.
#2065 posted by Spike [86.180.169.148] on 2016/02/14 05:40:07
seems that warning only got a code in revision in july, hence why its not present in the warning message you gave.
you'll need to update your copy of fteqcc if you want to blanket-disable that warning.
alternatively, because the warning is generated regardless of whether setmodel is a builtin or a qc wrapper, you can just do:
#define setmodel setmodel_spanishinquisition
#define precache_model precache_model_omgninja
before your builtin/wrapper definitions.
of course, that hack won't stop you from ever having the problem, and implies that you'll be lazy and forget the cases where it won't work as expected - ie: outside of initial spawn functions.
even fte+dp will display a warning if you setmodel without precaching first, despite them both supporting precaches any time (there may be some edge cases in dp regarding bsp models, iiuc).
either way, triggering auto-downloads mid-map is bad. hurrah for PREcaching.
#2066 posted by Spike [86.180.169.148] on 2016/02/14 05:54:12
regarding unary-not, !a&b always looked wrong to me, as a C programmer. The brackets don't change anything, but they do clarify things for people more familiar with C operator precendence. :P
 Cache Miss
#2067 posted by Preach [77.99.55.146] on 2016/02/14 09:45:38
of course, that hack won't stop you from ever having the problem, and implies that you'll be lazy and forget the cases where it won't work as expected - ie: outside of initial spawn functions.
If you've forgotten to precache a model you need, you're screwed either way. What it does is threefold:
1) Allows for external model files in e.g. func_wall (and since you can't know from the QC if the model will be "*10" or "progs/cog_lrg1.bsp", precaching everything that comes through just in case is the only safe way).
2) Permits you to reuse a spawn function which you've already called at the start of the map to create a fresh instance of e.g. a monster mid-game. This is a Don't Repeat Yourself principle thing.
3) Makes spawn function code a little bit shorter and tidier
The part 3 on the end there is more of a bonus, not the point of the code.
#2068 posted by necros [172.98.67.68] on 2016/02/14 15:31:34
thanks, spike! just picked up the most recent version (feb 11 2016)!
#2069 posted by necros [172.98.67.68] on 2016/02/14 15:34:57
note: suppressed 262 more warnings about unreferenced variables, as you clearly don't care about the first 10.
too funny. i need to go clean up this code...
#2070 posted by Spike [86.180.169.148] on 2016/02/14 18:44:34
@preach
1) yes, it avoids going through each func+trigger spawn function to ensure that there's a precache_model(self.model) line. I guess it depends how lazy you are.
it'd be nice if engines supported precaches any time, but this implies mid-game downloads and possible reliable-vs-datagram races and things (which would crash vanilla before any illegible server messages), both of which are nasty enough that the qcc(+maybe engine) should still warn if something isn't explicitly precached.
2) by all means wrap precache_model so that it doesn't crash outside spawn functions. wrapping setmodel will just hide things so that compilers cannot reliably detect it.
Ideally the server would only error if the precache is actually new... but considering how many people use crippleware engines, this ideal is admittedly laughable.
3) it would be better to make a 'presetmodel' function that does both, or something. at least then the compiler won't see either the precache or the set.
you'd still need a precache_model if you do an explicit setmodel elsewhere.
4) qcc trying to detect missing precaches is a nice idea, but also still a hack that can only see immediates, with hardcoded function names.
I fully admit that I'm biased towards one of those hacks. :P
@necros
you can use the verbose(aka: -v) option if you want a list of all of them instead of just the first ten.
or you can use #pragma noref 1 and #pragma noref 0 around them if you want the qcc to (mostly) ignore any unimportant defs, like unused builtins etc that you might find in dpextensions.qc (note that this is the mechanism used by fteextensions.qc to silence warnings about all that unused stuff).
Of course, you should only really use this if its meant to be maintained by someone else.
#2071 posted by necros [172.98.67.68] on 2016/02/14 21:08:40
thanks spike! yeah, i was doing them 10 at a time... this is much faster.
also, thanks for the noref pragma... where is the documentation for all these little tricks? the wiki i linked to earlier doesn't seem to have any other pages?
#2072 posted by khreathor [194.181.150.106] on 2016/02/15 15:42:40
Is there some good article describing how Quake's Lightmapping works? I tried to understand it from BSP format docs, but it looks like some black magic.
#2073 posted by necros [172.98.67.72] on 2016/02/15 16:30:39
lightmaps are basically just textures.
there are 64 'styles'
each face in a map can have at most 4 styles on it.
typically there's only one style, style 0 which is always on.
then there are 11 other styles that flicker and pulse and such. these are the ones you can select in the editor.
each time you make a target/targetname switchable light, the light utility reserves a new style number.
qc then changes the style via lightstyle function. these numbers start at 12.
it's important to note that the target/targetname has nothing to do with anything other than letter the QC pick up the style value that light.exe has added to the entity after compiling.
 I Think He Means Lightmapping
#2074 posted by Qmaster [70.195.68.32] on 2016/02/15 18:45:16
#2075 posted by metlslime [50.150.122.79] on 2016/02/15 19:47:36
I believe, switchable light styles start at 32
 Lightmap On In Dedicated Server Mode?
#2076 posted by Teknoskillz [73.142.34.180] on 2016/02/21 16:10:04
Is this hard to do from the engine? Could an extension be made so it can be done in QC ?
 Sound Isn't Looped
#2077 posted by madfox [84.84.178.104] on 2016/02/24 09:32:29
A static entity, with a precached sound runs a 11000hz wav in the right order.
Another setup with the same statements remarks the sound wav isn't looped.
I can't remember I looped the first sound. I start Cool, load the sample, save it as looped. Same outcome, not looped.
Audacity the same, saved looped, same error.
What is the cause of this well or not looped sound?
 @Madfox
#2078 posted by Teknoskillz [73.142.34.180] on 2016/02/24 21:13:18
I seem to remember once if the sound was in the /ambience folder, it always seemed to loop no matter the type. Try that and repost here.
 No It Doesn't
#2079 posted by ijed [200.73.66.2] on 2016/02/24 21:21:33
 Integrate
#2080 posted by madfox [84.84.178.104] on 2016/02/24 21:52:54
I had this earlier, but then Cool-150 adjusted the loop function.
Now I even can save the wav.
 Back To Gibs That Stick....
#2081 posted by Teknoskillz [73.142.34.180] on 2016/02/25 07:59:10
Revised the code and got them sticking to ceilings, with occasional bloodshowers, however if the ceiling is sloped, we need to probably check its angle and apply gravity in a "reverse" direction in some cases possibly. How to get the engine to do that, id say is a challenge.
But I went with MOVETYPE_NOCLIP to get it to slide straight down on the wall, and checkbottom works well to break it out of noclip so far. Im using Darkplaces with setmodelrealbox, so the model actually has what I refer to as a "mass" m basicly its not point size anymore...so you can set larger gibs so slide faster for realism. I updated the code here if anyone wants to take a peek or collaborate / add a tweak:
http://collabedit.com/phw6e
#2082 posted by FifthElephant [178.97.200.7] on 2016/02/25 11:01:57
Trying to get a brutal quake going?
 Experiment
#2083 posted by Teknoskillz [73.142.34.180] on 2016/02/25 18:54:15
yea, Brutal Doom was maybe where I first saw this back when I tried it. Curious how it looks in Quake. So far that code seems to work kinda well, but sloping surfaces need to be addressed.
 Modified
#2084 posted by Teknoskillz [73.142.34.180] on 2016/02/26 02:31:19
Updated the code again. Hopefully now it will know when its not in contact with the surface if its moved to a corner while traveling down, which does not rest on a floor. It ought to detach now and become a regular gib. Still need to test it though...yea all this for a Giblet, right ? :)
#2085 posted by necros [172.98.67.56] on 2016/02/26 05:23:22
i'm pretty out of it right now...... but can someone confirm this..?
basically, whenever there's a collision, in your .touch, you will have a normal of whatever the collision was??
i think with maths, you can generate a downward vector with that normal and gravity and set the movement that way with a MOVETYPE_FLY instead of noclip.
 Correct
#2086 posted by Teknoskillz [73.142.34.180] on 2016/02/26 18:16:04
I experimented with that a couple of years ago, thought it made sense and it does seem to return the right normal....at least in Darkplaces engine , not sure about others.
When you think of it, the collision code has to be ran to confirm a collision, and since the eng is likely using some kind of tracelines to determine collisions, makes sense they applied the results to trace_plane_normal somehow.
I ran it by Spike a couple years ago, he said he believes traceline is the best way to get the normal , and in some cases I guess so..but so far in my experiments for what I am crudely doing seems to work ok.
 Stick Gibs Update
#2087 posted by Teknoskillz [73.142.34.180] on 2016/03/11 20:18:26
Well, my new modified EntitiesTouching() code did not work too well to detect if the gib was no longer in contact with the surface it was sliding down, so I created a new function which seems to do the trick, and updated the code here [
http://collabedit.com/phw6e ]
For now I commented out the .pusher reference as maybe later we can account for moving BSP objects and handle those cases.
Right now seems to mostly work ok except perhaps the sticking ought not rely solely on its velocity , but also its vectoangles of (gib.velocity) with respect to the surface its hitting? So I suppose we could formulate a tolerance where if the angle is perhaps within +/- 15% of the angle the surface normal is at, then we can have it stick, otherwise make it bounce normally.
Anyone have an idea how to start on this ? Feel free to edit the code, the site lets you collaborate.
 Serious Engine Open Source
#2088 posted by DaZ [89.168.60.163] on 2016/03/11 21:17:58
#2089 posted by necros [172.98.67.30] on 2016/03/13 05:17:45
so... there's a +/-use... how can we (if possible) use this?
 Checking On Func_togglewall
#2090 posted by Preach [77.99.55.146] on 2016/03/28 13:48:01
There's a bit of hacky code in a func_togglewall and I wanted to understand why it's safe. The togglewall is turned non-solid by directly adding '8000 8000 8000' to its origin by, always putting it outside the maximum coordinate range (at least until some newer engines came along).
This violates one of the normal golden rules of QC, which is to always use the setorigin function to move an entity. Clearly in this case we get away with the trick, and I wanted to check if I understand why:
The purpose of setorigin is to make sure that when an entity is moved, the engine correctly links the entity. My layman's understanding is that linking makes sure that the entity is correctly renderer and collided against. The point for a togglewall is that we neither care if it renders correctly (it's invisible) or that it collides correctly (it's non-solid).
Getting right into the details of the collision stuff, normally entities are linked into particular regions of the map. Regions are an efficiency feature, so the engine can skip testing for collisions between entities far apart in the map. When we skip the call to setorigin the togglewall remains linked to the region it started in, which may be wrong for its new location. But this is OK: things in the region it started in keep checking if they collide with it, but never do because it's so far away. Meanwhile, it's not in the region for its new location, but in theory nothing should be in that region anyway, and we don't need those collisions either.
If the above is correct, then I assume when we reactivate the togglewall to move it back, the original region link is still in place. So we go back to colliding with things in the vicinity, without needing setorigin here either.
Am I somewhere near the mark? I know I've glossed over the case where entities straddle regions, and I'm sure some of the terminology is different. I really just want to be sure why we get away with it here, to check if the same trick is OK in similar circumstances.
 Is There A Way To Load Multiple Progs.dat?
#2091 posted by kalango [200.19.186.55] on 2016/03/28 15:34:02
Like, a mod for weapons,another for monsters, in a single game? FTE or Darkplaces wise...
Is that possible?
 No
#2092 posted by onetruepurple [95.160.159.161] on 2016/03/28 15:52:52
 @kalango
#2093 posted by Spike [86.139.74.157] on 2016/03/28 17:07:26
yes. it is possible with FTE. whether its practical is a different matter.
the addon* cvars allow you to name addon dat files to load within the ssqc vm. these addons can interact with other dat files with the externset+externvalue builtins, or entirely via fields+new spawn functions.
the catch is that the engine's builtins are only able to understand one set of globals, which means you tend to need to use externvalue(0, "&whatever") to get a pointer to the global from the main progs, along with some preprocessor magic to hide the uglyness of this.
function types are just references in qc, this means that addons can query+replace function 'variables' in other dats in order to hook them to do whatever the addon needs them to do.
(make sure you don't compile your addon.dat files with -O3, as this strips needed string information)
tldr: so yeah, you can do it in fte. whether its actually practical to do so is a different matter. generally its only usable if you can make your addition entirely self-contained.
#2094 posted by necros [172.98.67.52] on 2016/03/29 01:26:26
that is really cool. unfortunately, in order for mods to be truly modular in a way that would work for that, you'd really need to code with that modularity in mind. :(
 Awesome! Ty Spike
#2095 posted by kalango [200.19.186.55] on 2016/03/29 15:12:00
 Preach
#2096 posted by ijed [200.73.66.2] on 2016/03/29 16:43:52
That was my conclusion as well.
I did a bit of work with these (having them visible and used for other things as well) and decided that the hack is just what it appears to be. The position is never updated just out of laziness rather than for a specific need.
I tested resetting their position to see if it changed something in the map but couldn't notice any difference. But my knowledge is more limited than yours on these matters.
 Preach
#2097 posted by Spike [86.139.74.157] on 2016/03/29 17:20:01
setting force_relink (eg, triggering a teleporter) or reloading a game will force those entities to be relinked in whatever position that they're currently in.
if they're then moved back then they'll be non-solid in their original location.
if neither of those two events happen, then the entity's pvsbits and areanodes won't change, so as long as its reset to the original position it was setmodeled in, it'll be fine.
additionally, fte can trigger relinks from vid_restarts (worldmodel is reloaded, so the old pvs is possibly no longer be valid). I assume other engines might do the same.
 Two Replies In Reverse Order
#2098 posted by Preach [77.99.55.146] on 2016/03/29 19:11:40
setting force_relink (eg, triggering a teleporter) or reloading a game will force those entities to be relinked in whatever position that they're currently in.
I can understand the concern with save games, it seems to me that the hack should fall down there. I tried the following to test it:
1) trigger a togglewall to "become non-solid" i.e. leave the map
2) make a save file
3) load the save file
4) trigger the togglewall again to bring it back into the map
This doesn't exhibit a bug, the wall worked fine - it collided with me, even though it shouldn't be in the correct areanode. Is there a chance that areanodes are calculated with the coordinates "wrapping round", so that the precise distance displaced is saving the day?
The position is never updated just out of laziness rather than for a specific need.
I wondered if the intent might be to avoid "trigger in clipping list" type errors, the kind caused by changing things during a physics update. Potentially a togglewall can be triggered during a touch function.
#2099 posted by metlslime [159.153.4.50] on 2016/03/29 21:41:24
that's interesting because the func_laser in rubicon2 calls setorigin in its use function, and i don't think it causes any problems.
 Might Be Remembering Wrong
#2100 posted by Preach [77.99.55.146] on 2016/03/29 22:28:40
I'm mostly backing this up with a comment from client.qc
// we can't move people right now, because touch functions are called
// in the middle of C movement code, so set a think time to do it
But I guess I must be misinterpreting it if I'm banning setorigin during a touch function, or else how would a trigger_teleport hope to function?
Is it changing the solid status of an entity which is forbidden then? Is it particular to messing around with a trigger?
#2101 posted by necros [172.98.67.30] on 2016/03/30 04:03:15
i remember having problems with doing setorigin in touch... but i think it only happened with triggers of some kind. sorry, really long ago, forget all the details. :S
#2102 posted by Spike [86.139.74.157] on 2016/03/30 05:34:33
SV_TouchLinks walks through the various triggers in a fairly lazy way. you can relink non-triggers inside trigger touch events, but if you relink any solid_trigger entity there then the loop can end up referring to the wrong entity, potentially resulting in references to null or infinite loops. sometimes you might be lucky and get away with it, it really depends on the ordering.
this can be seen on e2m2 - shoot one button then jump across and you'll touch a trigger that killtargets another trigger, resulting in a crash.
non-triggers touching non-triggers should be safe, as the node-walking is separated from the qc callback, limiting movements to touch only one other solid entity.
because triggers and non-triggers use separate node lists, relinking the player won't hurt the trigger lists, which is how come teleporters never cause any problems.
by relinking, I mean calling setmodel/setsize/setorigin, or alternatively removing an entity.
bug-fixed engines will probably just build a list of the triggers that need touching and *then* trigger the events if the triggers were not removed by a different trigger, thereby avoiding the crash at the risk of dropped touches (if its a player then it'll just get touched next frame anyway, although monsters might not re-trigger it any time soon if they stop walking at that point).
 Rcon Tool
#2103 posted by Teknoskillz [73.142.34.180] on 2016/04/15 05:30:25
Ok, Im needing something that can remotely rcon Quake engines, mainly pq for now. Turns out if you have a server on 2 ports, the rcon commands always wind up heading to port 2600 by default. SO you can use rcon_address and rcon password fine, and even status will show up ok on the non std port but any command telling it to change a setting winds up going to port 26000. SO I found this small app that claims to be able to rcon to Quake servers: [ http://www.codeproject.com/Articles/21885/Send-RCON-Commands-to-Quake-Based-Games ]
They want an email address sand pw so the dl is accessable, so I think any email address will work, it dont seem to send out a verify, then you can just dl the code.
So its C language, and I have had such rotten luck using Visual Studio trying to compile a Quake engine, but since this one was small , decided to try. Turns out I have Visual Studio 10, and it said it needed to convert, which it did, and seemed that it was successful, so I clicked on the proj file, and did a build, and to my amazement, it built an exe in bin/release and also in obj/release. However my excietment was short lived, as the app does run, when you enter a server address and pw and command, it locks up indefinately and has to be shut down in task manager.
Anyone here have some advice on what Im doing wrong or is the code itself just crappy?
 Modify Player View Pitch Through QuakeC
#2104 posted by bloodsnipe [162.228.24.207] on 2016/04/17 00:49:29
Is this possible? I notice an entity member idealpitch but changing it doesn't make a difference.
I'm trying to add gun climb, where firing a weapon makes the player look up.
#2105 posted by necros [172.98.67.93] on 2016/04/17 02:22:15
yup, totally possible. set .fixangle to 1. the player's view will snap to whatever is in .angles.
#2106 posted by Spike [31.51.131.152] on 2016/04/17 04:31:40
nnnnnoooooo!
you can spam fixangles as much as you want. each time will cause the player's view to snap to something that they were not aiming at at the time.
this is especially bad over a network. you simply cannot use it for only pitch or only yaw.
it can be kinda rough even in single player, even a single frame's delay will snap you back to your yaw angle from the previous frame. repeat and your angles are now locked.
there is a .punchangle field that you can use to bias the pitch angle, however, it tends back towards 0 and there's not really anything you can do about that. It WILL judder regardless, especially in QW where you'll probably overcompensate and cause it to go completely haywire.
if you want full control over the camera angles, or the client->server angles, the only place you can reliably do that is clientside. Ie, in csqc. Doing it serverside will just result in fighting with the client, and the lag (even in single player) will prevent you from reconciling.
#2107 posted by bloodsnipe [162.228.24.207] on 2016/04/17 08:44:30
Okay, so I tried fixangles and the behavior is very unexpected. Spike (is that you, Spoike?) is correct, I've tried it in Quakespasm, Darkplaces, FTEQW and it does snap to something i wasn't aiming at (even after using angles/v_angle = angles/v_angle + 'x y z') in all of them.
punchangle is also cosmetic and doesn't effect gameplay. I'm messing around WriteEntity() now... will let you know how that goes...
#2108 posted by bloodsnipe [162.228.24.207] on 2016/04/17 09:26:06
Got it i think. After I calculate the new angles, I use WriteByte ( MSG_ONE, 10 ); Now, I dont know if this adjusts v_angle or angle, but hey... it works for now. Here is the code chunk for anyone interested;
ang_x = -8 - random() * 2;
ang_y = random() * 2 - 1;
ang_z = 0;
ang = ang + self.v_angle;
msg_entity = self;
WriteByte ( MSG_ONE, 10 );
WriteAngle( MSG_ONE, ang_x );
WriteAngle( MSG_ONE, ang_y );
WriteAngle( MSG_ONE, ang_z );
I'll throw together a tut soon (hopefully)
 Impulse Processing Takes Place After Physics?
#2109 posted by bloodsnipe [162.228.24.207] on 2016/04/21 06:46:42
I'm wondering why is the W_WeaponFrame() function called in the PlayerPostThink() and not in the PlayerPreThink(), moving it doesn't appear to make a difference. Is it arbitrary? Or, did the developers intend to queue command processing for next frame after all entities had been processed?
I know pre and post run before and after player physics processing (or is it before and after all entities have had their physics processed?), when does the animation tie in to the flow of a single game step? In my own WIP game engine, the flow at every step is:
1) Capture events
2) Process logic/AI for all 'actors'(entities)
3) Animate all actors
4) Run physics on all actors
5) Render everything
 Different Weapon Pickup Sounds Crashes Quakespasm
#2110 posted by Daya [81.250.122.194] on 2016/04/22 14:13:58
For my mod, I made sure that each weapon pickups have their own sounds. Same thing for armors and ammo boxes.
It works without a problem on darkplaces, but picking a weapon in quakespasm stops the current game and displays this:
http://image.noelshack.com/fichiers/2016/16/1461326522-spasm0000.png
Here's my code for armors:
http://pastebin.com/7DywCzPm
My code for ammo boxes:
http://pastebin.com/eKKZUVqu
And finally, my code for weapon pickups:
http://pastebin.com/Mwr4NtnG
As you can see, I used for all of them that "self.noise" trick that allows me to add different sounds for each items.
I find it wierd because picking up ammo boxes with that method in quakespasm doesn't crash it, even though they use the same technique. At first I thought that was because the whole "self.noise" root declaration was put after all the individual weapon pickup lines, while it was put before for the ammo boxes. So I tried to do that for the weapons, but while testing in darkplaces the weapon pickup sounds don't play.
#2111 posted by metlslime [159.153.4.50] on 2016/04/22 20:32:11
you need to precache sounds in the spawn functions, not the touch functions. Your armor and ammo code are doing it correctly. Your weapon code is doing it wrong.
 Thanks, It Worked!
#2112 posted by Daya [81.250.122.194] on 2016/04/22 21:44:59
 Source Code For Mission Pack #2? + Other Things
#2113 posted by Daya [92.142.135.81] on 2016/04/24 21:28:29
I had someone test my first schlossherr map, and he picked-up the MegaHealth item in my map, and because they share the same itemslot, he got the BFG as well.
With this, coupled with the fact that I want 2 extra-items after being done with the BFG, I remembered that mission pack #2 had an items_2 thing that lets you store more items. Thing is, my google-fu is weak and I can't find its sourcecode, even in ModDB. Would anyone be kind enough to link me to it?
Another thing, since I'm adding additional weapons, how can I add extra HUD icons?
One last thing, Back when I was asking questions about my BFG problems regarding the projectile penetrating enemies, I recall someone saying something like "destroy the projectile which makes a new one with the same trajectory as the original projectile", but what's the way to pick up those coordinates and use them?
 Source Code For MP2
#2114 posted by Preach [77.99.55.146] on 2016/04/24 23:25:31
I can't seem to find a regular download for the rogue QC either, but I did find a github account with it
https://github.com/bazilio-ua/q1.progs/tree/master/original/rogue/progs
It looks like some modifications have taken place since, but if you track back to the initial commit it's probably how the original files looked. Hopefully...
Another thing, since I'm adding additional weapons, how can I add extra HUD icons?
You only have three options as to how the HUD works. You can have the HUD like it is in vanilla, or the HUD from mission pack one, or the HUD from mission pack two. You can customise the icons themselves, but there is no way of rearranging them or adding more than what the mission packs have. The mission packs got special customisations to the engine code before the source was released, it's not something the QC gives you any ability to change.
Incidentally, items2 was actually introduced in hipnotic, not in rogue, so you want the mission pack 1 source code really!
 Had Rogue's QC From The Start
#2115 posted by Daya [92.142.135.81] on 2016/04/25 00:51:09
Re-looking at it, and I have items2 defined in hip_def.qc (included in progs.def), which begs the question: if it was, then how come I have trouble adding items then? Or should I put my new weapons and items declaration from defs.qc to hip_defs.qc? Or is there something else that I'm missing?
 Progs.src
#2116 posted by Preach [77.99.55.146] on 2016/04/25 18:26:05
Two minor ideas. Firstly, make sure that it's being included in the compilation. Take a look at the progs.src file and check that hip_def.qc is in there.
The other think to think about is that you select between the three HUDs on the command line, not in the QC. So make sure you're using -hipnotic or -rogue on your command line when you launch Quake. Also keep in mind that you need the end users of your mod to remember to do that too! I expect lots of people forget with Quoth and don't see the plasma gun icon...
 Special Brushes Affiliate? (secret Doors, Platforms, Etc.)
#2118 posted by Daya [86.192.84.88] on 2016/05/16 14:26:35
I'm asking what it is so I could properly made the BFG orb for my mod not to target them/make the orb explode on impact on them, and also so I can get around bleeding brushes when you hit them.
 Translated Article, I Cant Find An English One Right Now.
#2119 posted by mfx [85.180.43.54] on 2016/05/17 21:45:28
#2120 posted by mfx [85.180.43.54] on 2016/05/17 21:47:50
 Brush Entities
#2121 posted by Preach [77.99.55.146] on 2016/05/18 00:35:26
I'm asking what it is so I could properly made the BFG orb for my mod not to target them/make the orb explode on impact on them, and also so I can get around bleeding brushes when you hit them.
Clarifying question: You still want the orb to explode when it hits the rest of the world, just not platforms etc? Is there any other exception you want the orb to explode when striking?
 I Want It To Explode On Any Brushes, It Usually Goes Through Enemies
#2122 posted by Daya [86.192.84.88] on 2016/05/18 14:58:26
who get gibbed when hit by the orb, so my guess is that it will go through buttons and doors that need to be shot if I leave it at that.
Speaking of which I still don't know how to remove the orb and THEN create another one with the same XYZ coordinates it got when it was first shot, because leaving at that makes the orb bounce off.
Another thing, I've been trying to clean my weapon cycle code by looking at scourge of armagon's code, but things get more complicated when you have weapons that share the same slot and have different ammo consumption.
My code:
http://pastebin.com/fRKhfLVG
Compilation error message (can't really find what's wrong with the whole oldimpulse thing and all):
http://pastebin.com/cFTRBHVB
Hipnotic's part of the code (just in case):
http://pastebin.com/J7fnWur4
 Daya
#2123 posted by Preach [77.99.55.146] on 2016/05/19 18:44:26
I feel more confused after your clarification. At the moment does the orb
1a) explode when it hits the world - yes/no
1b) explode when it hits a door - yes/no
Would you like it to
2a) explode when it hits the world - yes/no
2b) explode when it hits a door - yes/no
Please delete as applicable.
 Preach
#2124 posted by Daya [86.192.84.88] on 2016/05/19 21:09:49
1a yes
1b yes
Actually I just tested in the first map, and while it targets nearby shootable brushes, it kind of makes for a Power Bomb effect like in Metroid, where detonating one would reveal every secret tiles on the screen, so I think it's something I can leave on (still looking for a solution for those "custom explosion sprite doesn't appear" and "how do I make a new orb that shares the XYZ coordinates after removing the original once it collides with an enemy that got gibbed on direct impact?" problems).
 Man Daya
#2125 posted by Preach [77.99.55.146] on 2016/05/19 22:46:25
There were four question, I still don't understand what part of your post is what it's currently doing and what part is how you want it to be different.
 Alright So
#2126 posted by Daya [86.192.84.88] on 2016/05/20 00:56:15
1. Me being afraid of the BFG orb doing wierd things to special brushes (mostly secret doors, doors and buttons that need to be shot) was a false scare, so we're done with it
2. There's been a talk on the BFG orb ricochetting off a enemy who's been gibbed on direct impact, while the aim was to make the shot penetrate if the target gets gibbed on direct impact, and one solution was to remove the orb and make a new one using the same angle as the first one, to make it seem the orb goes through. I'm looking for how to code [remove orb] and [create new orb with the same coordinates as the first one at the exact same frame it first appeared].
3. When the orb explodes, it should leave a custom explosion sprite, but it doesn't. Wierdly enough, the blast sprite appears.
Code: http://pastebin.com/Q479dGGb
4. I'm currently having a problem with my weapons switching code, because if you have the nailgun or super nailgun in your inventory and press 4/5, it says "no weapons". So I fiddled around while looking at scourge of armagon's code, but when you have weapons that share the same slot AND have different ammo consumption (super nailgun=2 & gatling gun=1 ; Thunderbolt=1 & BFG9500=30) I run into trouble because of scourge's code. And I got a big compilation error for that. I'm also looking for ways of isolating both the "not enough ammo" and "no weapon" code so I can play a sound for each of them.
Compilation error message:
http://pastebin.com/cFTRBHVB
Weapons.qc code:
http://pastebin.com/0G7g8h34
Scourge's w_changeweapon:
http://pastebin.com/0m9X14wP
Hope I've been clear here.
 Fixes
#2127 posted by Preach [77.99.55.146] on 2016/05/20 07:54:44
2. This kind of thing is hard to diagnose without playing around with it, but something to try: After you set velocity on the orb when you first launch it, add a line
self.pos1 = self.velocity;
This saves the velocity it should have.
In the collision code, add the reverse line
self.velocity = self.pos1;
This restores the missile's velocity after a collision. Try it, and remove it again if it doesn't help.
3. Twice in that code you write:
BFG_Expl();
remove(self);
This is setting up the custom sprite, and then immediately removing it.
4. On line 1903 you have forgotten to comment out the bracket. This had made the compiler think that the function is over, so it doesn't understand why you're still talking about oldimpulse.
 Most Things Are Fixed But
#2128 posted by Daya [86.192.94.150] on 2016/05/20 11:20:26
The self.pos1 thing makes the orb full-stop in thin-air when it collides with an enemy who gibs on direct impact.
Is there another thing I could try?
 Update
#2129 posted by Preach [77.99.55.146] on 2016/05/20 17:47:48
That's because the first bit needs to be a bit different to what I said:
bfgsphere.pos1 = bfgsphere.velocity;
is what's needed. In the function where the orb is launched, self is the player and bfgsphere is the orb, so we need to save the value elsewhere.
 Still The Odd Ricochet
#2130 posted by Daya [86.192.94.150] on 2016/05/20 20:59:34
 # In Quake Compiling
#2131 posted by Ruin [108.197.121.196] on 2016/06/13 06:31:40
Hi,
Today I downloaded the Transfusion SDK in order to start up on that project where the dev team left off. The source code comes with their own custom compiler, BQCC (Blood Quake C Compiler) which seems to have some types defined which frikgui.exe does not have.
The problem is, I'm more comfortable with frikgui.exe, because it has a far more sophisticated interface, along with tools for debugging any warnings or errors. Does anyone know what this means--
"Error Q548 common.qh(95) "#" is not a type
Does anyone know how I can make frikgui.exe recognize "#", along with any other types?
#2132 posted by Baker [50.4.45.41] on 2016/06/13 07:15:54
Code written with customizations specifically for a certain QuakeC compiler aren't going to compile except for that specific compiler.
So you'll either have to re-write the problematic lines by hand yourself to work with the target compiler or use a compiler that can compile the code unmodified.
 Baker
#2133 posted by Ruin [166.170.5.53] on 2016/06/13 07:53:32
Feared as much!
Ok, here I go.
Thanks Baker.
 Quakespasm Coding Help
#2134 posted by Shamblernaut [121.45.230.253] on 2016/06/13 13:40:56
Ahoy, so I've been trying to implement IRC support for Quakespasm. I'm trying to get it done for QExpo so that if any streamers want to have their twitch chat in game they can. Or if people want to play and shitpost on #TF or whatever. I've been using libircclient and have had some success but have come to an impasse where I have no idea what to do.
I'm wondering if somebody could look over my code and see if I'm missing anything that could be causing my issues.
I'm running a local server to test, which receives a connection from the game, but doesn't seem to keep-alive, it just times out. I have polling code, that just doesn't get called because the connection is never established.
I'm running linux, so I haven't compiled any libircclient libs or objs for windows, however in the base directory of the archive is a libircclient.o for linux. Which can be copied into the quake (source code) directory for compilation under linux.
Here are the lib irc client docs:
http://www.ulduzsoft.com/libircclient/
And here is the github link:
https://github.com/shaoner/libircclient
Most of the code exists in irc.c, with a few other bits and pieces in other files, a quick search for "shamblernaut" in files will bring up the other files that I've modified.
The thing I most need help with at the moment is figuring out why it isn't connecting. There are other things that don't work, but I'm confident I can get those working myself.
the console commands are:
irc_channel (include #)
irc_nick
irc_server
irc_port
irc_password (default set to "")
these are reflected via cvars saved in config.cfg
the above should be set first before connecting with:
irc_connect (connects with the above settings)
irc_join (sort of moot because it isn't connecting anyway)
At the moment all debugging info is printed to the console, so run from a command line.
Here is the source to my modifications:
https://www.dropbox.com/s/fsnv4y4r0oobswe/quakespasm-0.91.0-irc.zip?dl=0
Anyways, if somebody with some C and engine knowledge could have a look, that would be amazing.
Thanks in advance.
-Snaut
 I'm Selfishly Bumping This
#2135 posted by Shamblernaut [121.45.230.253] on 2016/06/18 09:33:02
for a bit more visibility. Has anybody had the chance to have a look?
#2136 posted by Baker [50.4.45.41] on 2016/06/19 01:31:23
1) Did you run the example irctest.c and test it against your irc server? What was the result and in the case of failure, the error code or response?
2) What IDE are you are using for debugging, setting breakpoints and stepping through code to look at the values of different variables and checking function results?
The library you are using looks like it requires at least an intermediate understanding of C to be able to use it since it uses callbacks, but if you are able to run the irctest.c successfully you might be able to successfully break it into pieces as-is and put it in the appropriate places.
 Hey Baker.
#2137 posted by Shamblernaut [121.45.230.253] on 2016/06/19 19:09:28
Thanks for the response.
So I was using just a text editor without using an IDE. In hindsight that was a terrible idea, so I've installed codeblocks as that is the project file that is included with quakespasm. So far the debugging tools look pretty reasonable.
Strangely the example executable doesn't work for me at all, they aren't even recognising the inputs from the console... weird.
Unfortunately the irctest application isn't ideal as it uses a loop function that freezes quake. It doesn't exit the loop once it has entered it. Instead the documentation suggests a select loop which I've added to my code.
The problem is way before that though, the select loop doesn't even get the chance to run, as it only does that once the connection is completed, whereas the app makes a connection, but refuses to keep alive. My IRC server spits back a timeout error.
I'll keep digging with the debugger, if you have any ideas I'd love to hear them.
#2138 posted by Baker [50.4.45.41] on 2016/06/19 21:00:07
You should get the irctest example working before trying to integrate it into Quakespasm, otherwise you can't be sure you are dealing with a working model.
Btw, your code in Host_Frame will trying ro connect over and over and over again but you may know this.
Yes, the sample code isn't ideal for Quake, because of the design of the loop but the first phase of anything is making sure what you've got actually works.
Taking shortcuts in coding and not doing things proper just leads to massive headaches, so you really need to get the sample working first to verify what you have will even work.
 Shamblernaut
#2139 posted by ericw [108.173.17.134] on 2016/06/19 21:22:47
Got the code compiling on OS X after a bit of fighting with the libircclient configure/makefile.
I think one issue is: if IRC_Connect_f is called with `irc_connect_bool` false, the irc_session variable will be an uninitialized pointer; then this line: "if (irc_is_connected(irc_session) == 0)" will access the bogus pointer, which should crash.
I think maybe you want irc_session to be static?
AddressSanitizer in clang/Xcode will catch this kind of thing; MSVC and recent versions of gcc also have similar functionality, I think.
 Shamblernaut
#2140 posted by szo [160.75.18.5] on 2016/06/20 10:15:07
For the record, the mainstream libircclient code
at sourceforge.net is at version 1.9, as opposed
to the old fork at github being back at 1.6:
https://sourceforge.net/projects/libircclient/
 Changing Music Playback?
#2141 posted by Daya [90.58.243.45] on 2016/06/20 10:22:40
So I've been thinking: the game's original code should mention going to the CD drives or the music, so is it possible to reroute the path from the CD drives to a custom one inside one of my mod's directory?
If yes, how can I do it?
I'd like to do that mostly so custom music can be done without dealing with engine-specific music playbacks, like Doom or UT.
#2142 posted by Baker [50.4.45.41] on 2016/06/20 12:46:05
Quake has support for a CD --- like an actual CD that plays in a 1990s CD player stored in the CDDA format.
https://en.wikipedia.org/wiki/Compact_Disc_Digital_Audio
Think of the answer as basically no, but if you were really, really determined and had a thing for fiddling with hex editors and old software maybe you could do it, like the guy who made Windows 95 run on his Apple Watch.
 Daya
#2143 posted by Kinn [81.131.159.129] on 2016/06/20 13:05:38
Are you talking about tricking a quake engine into reading the "cd data" from a location that's not the cd drive, without modifying the engine?
I don't have a scooby doo how you'd do it, but just wondered if that's what you're asking.
 @szo
#2144 posted by Shamblernaut [121.45.230.253] on 2016/06/20 15:37:47
thanks for the heads up, I had version 1.8, I linked the wrong version.
however, in the change notes in 1.9 from 1.8
"Fixed an error if the TCP connection to the IRC server couldn't be established under 250ms."
 Kinn
#2145 posted by Daya [90.58.243.45] on 2016/06/21 00:46:07
That's it basically.
If I can't do that however I can still have a workaround but it would only works for darkplaces and quakespasm/fitzquake, and including custom music would be tricky since you can only put track numbers.
But if there's a way to make quake play properly named music tracks even if it still looks for the CD location that would be great.
 @Daya
#2146 posted by Spike [86.139.74.224] on 2016/06/21 05:02:38
sorry for the mindless babble...
cd audio is handled by both engine AND the gamecode, which is not a happy combination - the engine can't use track names because the mod will somewhat stomp over it, and the mod can't use names because there's no standard way to actually do that (and would still get nuked on each map change).
so we're stuck with the server changing tracks on map changes, and maps+mods only using 0-255 values for track numbers.
despite CDs being mostly irrelevant now, dp+fte both still retain the cd command, with a distinction made between numeric and non-numeric tracks.
'cd play 5' plays track 5, but 'cd play omgwtf.ogg' plays the named file instead of a numbered one. this also works with 'cd loop foo' too, of course.
The coolest thing about this is that the following command works too:
cd remap TRACKNUMBER TRACKFILENAME
which is just great for remapping a track number to a named file (just don't expect it to change anything until the track is next changed). This can be great for config files.
the catch is that you're still fighting the svc_cdtrack that the server sends when you first connect, yay race conditions.
anyway, set world.sounds=0 inside worldspawn so that any cd tracks the server sends will be ignored and not give hideousness, and then send a 'cd loop foo' stuffcmd, or a 'music foo' stuffcmd to make quakespasm happy, while fte is happy with either (I'm too lazy to comment on other engines).
That way, you get full control over what is actually played.
 Spike
#2147 posted by Daya [90.47.73.225] on 2016/06/21 11:17:57
"'cd play 5' plays track 5, but 'cd play omgwtf.ogg' plays the named file instead of a numbered one. this also works with 'cd loop foo' too, of course. "
So what you're saying is, I can have a music track named "woah.ogg" and have in worldspawn's sounds line "woah" and it would play it on both Quakespasm/Fitzquake and Darkplaces?
Or must I use the world.sounds=0 thing, but then how would darkplaces play custom tracks if the commannd is different there?
 Thanks For The Help Everyone :)
#2148 posted by Shamblernaut [121.45.230.253] on 2016/06/22 15:33:44
Szo, Baker, EricW
I got it working... Now I need to polish it up :)
 On Music...
#2149 posted by Shamblernaut [121.45.230.253] on 2016/06/22 18:56:23
What would be the best way to implement progressive music, whereby entering into a mob filled area, the music becomes faster or different "battle music" fades in? Vice versa after the battle.
I'm not building this myself, I'm just interested how one might achieve this. I reckon it would compliment the game quite well.
Would you quakec? modify engine? use custom ambient sounds and triggers?
 How I've Implemented Before
#2150 posted by ijed [201.223.37.79] on 2016/06/22 19:17:32
Is to have two pieces of music playing at once and crossfade their volumes linked to another variable - usually something simple like player % health.
Both of the pieces of music work in theory when played at full volume together, but won't sound too good. The idea is that one piece is the 'action' music and the other the 'calm'.
Action starts at 0 volume and calm at 1 (full). As the player health drops and rises you switch the volumes - the lower their health, the higher the volume of the action music.
Never done this in Quake, although it wouldn't be difficult - could be done purely in qc, although you'd need to do some proper music editing using midis to turn off/on instruments and get the two identically sequenced but different sounding tracks.
 That Is
#2151 posted by ijed [201.223.37.79] on 2016/06/22 19:18:44
The lower the player health, the higher the volume of the action music and the lower the volume of the calm music.
 Interesting
#2152 posted by Shamblernaut [121.45.230.253] on 2016/06/22 19:35:41
I guess that's how the heartbeats work in some games too, except with volume and speed.
 Hmm
#2153 posted by Shamblernaut [121.45.230.253] on 2016/06/22 19:40:38
The variable I would use would be the quantity of mobs that have the player targeted as their enemy.
Or even total mob health as a percentage.
Probably with some kind of distance from player function as well. So that if you leave a single mob behind you won't constantly have battle music playing.
#2154 posted by Kinn [81.131.159.129] on 2016/06/22 20:08:16
/is playing oblivion
/a small crab emerges from a pond 25 yards away
EPIC BATTLE MUSIC
 @shamblernaut
#2155 posted by Baker [50.4.45.41] on 2016/06/23 03:31:07
Nice to see you got your modification working.
#2156 posted by Baker [50.4.45.41] on 2016/06/23 03:40:59
Probably with some kind of distance from player function as well.
Shamblernaut walks over a bridge. There are fish below.
Combat music ensues.
Shamblernaut finishes crosses the bridge. Combat music wanes.
Close call! Major skirmish averted!
#2157 posted by Shamblernaut [121.45.230.253] on 2016/06/23 08:01:52
do rottfish target the player out of the water?
 Rotfish
#2158 posted by Preach [77.99.55.146] on 2016/06/23 08:40:18
Monsters in Quake can't trace line-of-sight through water by default. wateralpha didn't exist in the original Quake. Preventing fish from alerting on players they can't attack is the main reason not to alter this behaviour.
ijed: There's a bit of a challenge in Quake that you can't modify the volume of a sound while it is playing. You'd have to build some kind of drum machine/sequencer in QuakeC and manually repeat the samples at different volumes - maybe like the procedural music in Left 4 Dead. I worry that variations in the frame rate would make that a bit wobbly.
Related joke: How do you know a drummer is knocking at your door? A: He speeds up
 Forgot About That :)
#2159 posted by ijed [201.223.22.68] on 2016/06/23 14:50:24
Constructing it by hand would allow you to do the knocking drummer effect though - upping the tempo as well as or instead of the sound volume changeover.
And there's always the classic HL1 method - ambient sounds only, and whenever a big fight starts play a short, scripted, one shot piece of music.
 Quakespasm-IRC-0.1
#2160 posted by Shamblernaut [121.45.230.253] on 2016/06/25 17:05:17
download link: https://db.tt/5jcVUJfD
screenshot: https://db.tt/5jcVUJfD
Hey
If possible I'd like to ask for some help compiling for windows and osx. I already have the linux version compiled and working (binaries included in the dropbox link provided).
Also feedback will be greatly appreciated.
Cheers,
Snaut.
#2161 posted by Johnny Law [67.188.146.229] on 2016/06/25 17:14:51
wrong screenshot link?
 Yeppers
#2162 posted by Shamblernaut [121.45.230.253] on 2016/06/25 17:17:32
 Dat Texture Filterering
#2163 posted by killpixel [174.48.226.83] on 2016/06/25 18:08:49
 @snaut
#2164 posted by Baker [72.168.128.153] on 2016/06/26 08:31:59
You might consider cross-compiling for Windows and testing the build under Wine, since you seem to understand all of that.
Which would keep you in driver's seat, which is seat anyone wants to be sitting in.
Here is a cross-compiling tutorial for CodeBlocks: http://forums.codeblocks.org/index.php?topic=3343.0
CodeBlocks Cross-compiling Wiki Entry: http://wiki.codeblocks.org/index.php?title=Code::Blocks_and_Cross_Compilers
Video Tutorial on cross-compiling: https://www.youtube.com/watch?v=3-yw-aD8CTI
Then you can make tweaks any time you want and build a Windows binary whenever you like.
 Add:
#2165 posted by Baker [72.168.128.153] on 2016/06/26 08:43:48
The Quakespasm team may already have a way of cross-compiling up a Windows build.
 Thanks Baker
#2166 posted by Shamblernaut [121.45.230.253] on 2016/06/26 09:08:05
Yeah, I'll sort it myself. I was trying to avoid clogging up my system with too many dev apps and libs, but last night I started down that road anyway.
Thanks for the links too. I'll dig a little deeper into it.
 @snaut
#2167 posted by ericw [108.173.17.134] on 2016/06/26 09:19:30
QS has some build_cross_*.sh scripts in the Quake directory, they'll need to be edited depending on your Linux distro/version.
The cross compile scripts I use for windows builds on my jenkins setup are here: https://github.com/ericwa/quakespasm-build-scripts (somewhat specific to my jenkins/ubuntu 14.04 setup. IIRC I started with build_cross_win32.sh and modified it a bit to work on that system.)
Pretty much all I installed with apg-get was the "mingw32" package plus "build-essential".
 New Link With Windows Binary
#2168 posted by Shamblernaut [121.45.230.253] on 2016/06/27 21:10:01
https://www.dropbox.com/s/iko14xmbe0gvwwq/Quakespasm-IRC-0.1.zip?dl=0
requires dlls, they're packaged in the source code if you don't have them
 Hi Guys
#2169 posted by spy [2.133.174.39] on 2016/07/02 16:20:48
is it possible to add the monster count to the scoreboard of game(s) Return to Castle of Wolfenstein and/or Sin and its MP
 Removing Keys With A Trigger/Fake Key
#2170 posted by Pritchard [121.219.228.6] on 2016/07/05 12:41:01
So, i'm looking to have the player collect a key in my map and then later be teleported in front of the door the key is supposed to open.
As part of this sequence, the door opens *jazz hands* for "effect" very slowly, beginning as soon as the player has been teleported. Unfortunately, this means that the player never actually touches the door to remove the key!
Basically, is it possible to either use some kind of entity setup to remove the key from the player without having them touch a door, or is it possible to create an entity that *looks* like a key, but isnt?
Thanks!
 Answered It Myself
#2171 posted by Pritchard [121.219.228.6] on 2016/07/05 13:07:24
I looked into it, and on the advice of others, decided that it wasn't possible to directly remove the key from the player in vanilla quake.
Instead, I settled for a solution where the player moves over an invisible door that is instantly removed when they touch it. That door takes the key from them at the appropriate time :D
 Well
#2172 posted by ijed [201.223.36.158] on 2016/07/05 15:58:25
 Trigger_earthquake
#2173 posted by madfox [84.84.178.104] on 2016/07/05 16:57:03
I want to use the earthquake trigger, but I only need it once.
So I use the killtarget option but it doesn't seem to work that way.
The killtarget is allready used for starting and stopping the earthquake within a given time.
I only need it once, but when I use the killtarget on it, it just goes on triggering the earthquake all the time.
What is going on there?
 The Shake
#2174 posted by ijed [201.223.29.216] on 2016/07/09 03:57:50
Is not being turned off, and it probably works independently of the trigger itself, being a looped function.
Try triggering the earthquake entity again instead of killtargeting it.
Should work, but I don't know what code base you're using.
 Thunderstood
#2175 posted by madfox [84.84.178.104] on 2016/07/09 07:04:50
I got two codes, one with only an earthquake.qc and the one from DoE. They both seem to act the same.
killtarget is allready in use, and there's no way to calm it.
I thought on trigger_once wait -1 but it fails.
 Quake Code
#2176 posted by Mike Woodham [109.146.55.41] on 2016/07/09 11:56:51
I remember using a one-off earthquake in FMB-BDG2 and I can see from the map source that I used a trigger_MWquake, which suggests I wrote or adapted some code.
I don't have the source anymore (I have no idea why not as I still have the map files?) but you could decompile the progs in that and have a look for the code I used.
 I Believe
#2177 posted by Qmaster [50.45.35.231] on 2016/07/09 13:47:47
there should be a trigger_earthquakekill entity. Check the rogue or hipnotic entity fgd's.
#2178 posted by necros [172.98.67.135] on 2016/07/09 20:08:24
from gtkr def for rogue:
/*QUAKED trigger_earthquake (.5 .5 .5) ?
The Earthquake generator.
Anytime a person is in an active
field, they shake. If the trigger is a
target, it will be OFF until triggered.
It will then toggle between ON and OFF.
weapon - richter scale of movement
(default 40)
weapon - if you give a weapon value of
40, the X and Y displacement
can vary between -20 and +20, a range of 40.
*/
i don't know why modern editors other than radiant don't include the description text. it's very useful!
 Earthquake Active Field
#2179 posted by Mike Woodham [109.146.55.41] on 2016/07/10 09:08:16
Ah, yes, that was the restriction that made it not as useful as I wanted, so I adapted the code to make it switchable only.
/*QUAKED trigger_mwquake (0 1 0) (-8 -8 -8) (8 8 8)
A switchable only earthquake trigger.
Keys:
"delay" - duration of the tremor
"weapon" - richter scale of movement (default 40)
(Funny how I have kept the BspEditor, the entity defs and all my map files, yet not kept the code - this is really puzzling me as I don't usually throw anything out e.g. 10,000 of my own photographs at 24meg each, half of which I will never look at again? I have to get to the bottom of this; I must have some HDDs tucked away somewhere.)
 Decompiler?
#2180 posted by Mike Woodham [109.146.55.41] on 2016/07/10 13:39:00
Can anyone suggest a decent progs.dat decompiler. I realise I wont get my notes included, which may be s stumbling block for me, but I now have a bee in my bonnet about getting to look over the code I wrote.
I have tried frikdec from 2002 but it fails to retrieve all the modules and doesn't do very well with those that it does.
 Earth Quake Killer
#2181 posted by madfox [84.84.178.104] on 2016/07/11 00:16:30
I tried to understand the earthquake.qc.
I extracted it from the SoA code and found client.qc and defs.qc changed as a earthq.qc.
Only using the earthq.qc is usefull but there are eight parms in use.
void() earthquake_rumble
void() start_earthquake
void() stop_earthquake
void() earthquake_touch
void() earthquake_use
void() trigger_earthquake
void() kill_earthquake
void() trigger_earthquake_kill
What I found is that the trigger_earthquake_kill is in use for the delaying the earthquake.
So when I tried to add a new one to kill the earthquake for ever doesn't work.
OK. So keep out of the area where the trigger_earthquake happens will do, but then I keep tat thunder sound throughout the level.
 Divided By 64, Multiplied By 85. What The... ?
#2182 posted by Izhido [181.194.213.65] on 2016/07/18 20:37:09
When checking vanilla's texture loading code, I found the following line, in both software and GL rendering:
pixels = mt->width*mt->height/64*85;
That is later used to allocate space for the incoming texture. My question: why do we need to take the amount of space needed for a texture, divide it by 64, and then multiply it by 85? What does those numbers even mean?
(Could it be that somebody was trying to cover up for a hard-to-find bug in the engine? Seriously, I have no idea...)
#2183 posted by Baker [50.4.45.41] on 2016/07/18 20:55:59
It's not a bug.
The calculation is the formula for adding the 3 levels of mip textures that software Quake uses to determine the byte size.
main mip1 mip2 mip3
64x64 ... 32x32 ... 16x16 ... 8x8
 Embedded Mipmaps.
#2184 posted by Spike [86.140.27.22] on 2016/07/18 21:01:26
assuming count is 16*16 (the minimum allowed):
count + count/4 + count/4/4 + count/4/4/4
256 + 64 + 16 + 4 = 340
giving a ratio of 256:340. simplifying that gives 64:85.
thanks to textures needing to be a multiple of 16, textures are guarenteed to be a multiple of 256 pixels, so dividing by 64 is safe.
this might not be true if you tweak your renderer to misalign the 1:16 lightmap ratio, but this sort of thing would break software rendering.
most gl engines just discard the original extra levels and use only the top-level image, so maybe you just want to nuke that part entirely.
 Ooh...
#2186 posted by Izhido [181.194.213.65] on 2016/07/18 21:13:39
Embedded mipmaps!
I see what you mean now. In fact, vanilla GL code actually does discard the incoming mipmaps. This happens in GL_Upload8(), which calls GL_Upload32() after copying the texture into a static defined trans[] array (ewww) containing only the bytes of mipmap 0.
Seems like they were in a hurry to deliver the game. What d'ya know? :)
#2187 posted by Baker [50.4.45.41] on 2016/07/18 21:40:53
Seems like they were in a hurry to deliver the game
They already delivered the game. Quake was a DOS application (quake.exe).
GLQuake was an after the fact unsupported release several months later. WinQuake, the Windows version of DOS Quake, was also an after the fact unsupported release.
Quake release date: July 22 1996
GLQuake: January 22, 1997
WinQuake: March 11, 1997
 Carmack Wrote GLQuake In A Weekend
#2188 posted by onetruepurple [95.160.159.80] on 2016/07/18 21:59:52
(And it shows)
 Heh, I Wish I Could
#2189 posted by Izhido [181.194.213.65] on 2016/07/18 22:07:25
do that in a weekend. I spent 1+ month doing my GL ES port :)
 Fitzquake Problem
#2190 posted by komagama [151.30.217.43] on 2016/08/19 13:00:18
Hoping it fits in this topic.. I have to say that all Fitzquakes do not work with Minigl 3dfx drivers .
I need that because I play Quake on a rather old pc and need those extra-frames !
 3dfx
#2191 posted by Spike [86.140.26.152] on 2016/08/19 14:56:29
try the mini-driver from quake3, it should be more complete (in that it includes support for vertex arrays).
 @komagame
#2192 posted by Baker [50.4.45.41] on 2016/08/20 19:30:08
If this is that Windows 98 machine, if you upgrade it to Windows XP, your choices grow pretty substantially.
I have to assume you must have enough RAM.
 String Command
#2193 posted by [73.142.34.200] on 2016/09/02 17:35:14
Is there a command that will take the 1st (x) number of chars in a string and let you compare them? for example , to know if we are doing episode 1, take the 1st (2) from the mapname string (e1) ? Possible ? I am using Darkplaces and there are some new string built-in extensions but they dont sem to be able to do this afaik.
#2194 posted by Spike [86.180.174.8] on 2016/09/02 20:18:16
if (substring(mapname, 0, 3) == "e1m")
then its probably episode 1.
float mapnum = str2chr(mapname, 3)-'0';
if (mapnum >= 1 && mapnum <= 8)
then you know which map number it is.
 Uh Oh
#2195 posted by Qmaster [70.198.45.168] on 2016/09/02 21:49:08
Is there a limit to how many functions FTEQCC will compile?
I'm trying to compile AD but it gives me this error unless I comment out a couple files from progs.src:
********** ERROR **********
Too many types
Error in <filename near end of list>.qc on line <line number depending on which other file(s) I've commented out>
 Update
#2196 posted by Spike [86.180.174.8] on 2016/09/02 23:08:47
that got fixed a while ago. hence why the code was released without those files commented out. :)
 @newhouse
#2197 posted by Baker [50.4.45.41] on 2016/09/09 08:49:13
If you can actually code, you are probably mostly better off learning how QuakeC works
HOW TO USE QUAKEC
0. QuakeC tutorials ---- MAJORLY useful
1. QuakeC source code
2. FTEQCC compiler - Compiles the QuakeC source
Extract the fteqcc executable to the folder with the QuakeC source code and double click it and it will compile up a progs.dat. That is what runs and is hiding inside quake/id1/pak0.pak. You need Pakscape to open pak files.
3. Pakscape Pak Editor Open/edit pakfiles.
4. QuakeC help forum (deadish) with useful reference threads
5. QuakeC specs
6. Links and References (very useful)
The QuakeC source code for progs 1.06 is standard Quake, it isn't Arcane Dimensions, but Arcane Dimensions, for example, is open source and if you were interested would be able to compile Arcane Dimensions following similar steps.
 @baker
#2198 posted by Newhouse [188.238.86.109] on 2016/09/09 16:52:11
Thanks, though I'm still studying, yet wanting to map more.. let's see how much time there will be left for learning this QuakeC during this year.
I will save your post for later use*
 @baker
#2199 posted by Newhouse [188.238.86.109] on 2016/09/09 17:00:23
Was my post flagged as spam, or did I even post here anything? What was I even asking.. but anyway, yes I have experience from programming C#/C++, but I was mostly working on user interfaces.
 Zero-Length Strings
#2200 posted by Preach [77.99.55.146] on 2016/09/11 01:00:42
Finally got around to writing up the killtarget bug which was plaguing Newhouse during Map Jam 7.
https://tomeofpreach.wordpress.com/2016/09/10/zero-length-strings/
It's actually something that could affect other QuakeC code as well, so worth a look if you're working on a mod at all.
#2201 posted by Spike [86.139.73.136] on 2016/09/11 02:00:02
fteqcc -Wall
will give a warning for that (and a few other things that will just annoy people)
fteqcc -Fifstring
will just automatically treat if(str) as if(str!=""). which is fine until you need to actually distinguish (like eof vs a blank line). if((int)str) can be used in that case.
 Use Case
#2202 posted by Preach [77.99.55.146] on 2016/09/11 09:26:41
Scary part is while I was writing the article I thought of an actual use case outside of extensions like eof vs blank line! For func_breakable there are are templates which if chosen will fill in default values in fields which haven't been set. In these cases, you can explicitly override a template which sets a field by setting a "" value.
Even if -wall is a bit too noisy to use permanently, it'll be a handy tool to use once and pinpoint all the instances that currently exist in the code to fix.
 Is My Compiler Or The Files?
#2203 posted by Johnison Boa [200.28.212.247] on 2016/09/22 00:23:05
I am opening fteqccgui.exe in mac with wine, but I don't know if my problem is this compiler or are the qc files I downloaded, I can't compile fine; because all qc files have string errors and using /**/ I cannot solve my problem.
H3LP
#2204 posted by Baker [50.4.45.41] on 2016/09/22 00:29:18
Are you able to compile standard Quake progs.dat 1.06 ok? http://www.quake-1.com/files/sourcecodes/kits/progs106.zip
 But...
#2205 posted by Johnison Boa [200.28.212.247] on 2016/09/22 01:02:00
standard progs, but with some of SOA & DOE content, 1 monster of SOE also
#2206 posted by Baker [50.4.45.41] on 2016/09/22 01:05:57
Does standard Quake progs 1.06 compile?
YES | NO
You are trying to figure out if problem is your code or compiler right? That is how to find out.
 Quake Progs 1.06
#2207 posted by Johnison Boa [200.28.212.247] on 2016/09/22 01:28:17
thanks, this works fine, so the problem was my old code...
#2208 posted by Baker [50.4.45.41] on 2016/09/22 01:49:27
See, haha.
 Step 2
#2209 posted by Johnison Boa [200.28.212.247] on 2016/09/22 03:27:05
to put new monsters from doe & soa to my progs.scr, what more goes with the respective qc of monsters?
#2210 posted by Baker [50.4.45.41] on 2016/09/22 03:46:52
This page loads slow as hell --- but it will eventually load ---
https://web.archive.org/web/20120213005405/http://www.inside3d.com/tutorials.php
It has monster tutorials at the bottom.
This page has monster mods
http://www.gamers.org/pub/idgames2/quakec/monsters/
You might look at spider21
http://www.gamers.org/pub/idgames2/quakec/monsters/spider21.zip
But ironically, I don't actually know QuakeC but rather just know where those resources are -- so I'll step out. ;-)
/Baker distracts Boa with "Hey look, a nickel!" and sneaks out the back door.
 Thanks
#2211 posted by Johnison Boa [200.28.212.247] on 2016/09/22 04:45:21
thanks for helping but I don't understand jokes in english, I'm chilean
and fine...
 Hey Guys
#2212 posted by Shamblernaut [121.45.237.124] on 2016/09/27 22:28:02
Is there an exhaustive list of functions that are available via quakec for vanilla quake?
#2213 posted by Baker [50.4.45.41] on 2016/09/27 22:34:37
1) Maybe see post 2197
2) Maybe read defs.qc in the progs source
3) Maybe see bottom of pr_cmds.c in the engine
#2214 posted by Spike [86.169.38.94] on 2016/09/27 22:36:08
try vanilla's defs.qc...
and bear in mind that a few of the args are wrong (eg: droptofloor does NOT take any args, and certainly not those of walkmove. yay copypasta bugs.).
#2215 posted by Shamblernaut [121.45.237.124] on 2016/09/27 23:02:21
cheers guys
 Entity Naming Conventions
#2216 posted by Qmaster [50.40.202.177] on 2016/10/06 07:02:33
Func, trigger, monster,info, you know the basics. My mod is getting...out of hand as far as multiple naming conventions go. I'm considering unifying the names of borrowed entities under Source engine's naming convention but still allowing the old entity names to keep from having to redo all my maps in progress...should I bother to nitpick this?
I'm thinking of using prop_ instead of misc_ or mapobject_; env_ instead of fx_ or misc_; logic_ instead of info_ or trigger_ (point entities where applicable of course); as examples.
Sort of thinking out loud here. I'm even tempted to go so far as to use npc...no no I'll leave them as monster_.
 Diff Program
#2217 posted by Qmaster [50.40.202.177] on 2016/10/06 07:05:25
Anyone have a good simple diff utility for telling if files are the same or not when merging folders and keeping the different ones but renamed?
#2218 posted by Baker [69.47.142.25] on 2016/10/06 08:32:25
WinMerge does a great job. ExamDiff is supposedly the King. WinMerge is free and awesome. ExamDiff might be available as a free trial if they still do that.
 Just Curious About This
#2220 posted by czg [213.113.209.223] on 2016/10/18 18:56:47
Every frame I need to check if a fairly small (5-15) set of entities is within a certain radius of the player.
Naive approach is to use findradius each frame and act on the results.
My current approach is to have a linked list that the entities in question add themselves to on spawn, iterate through that each frame and check for distance.
Am I prematurely optimizing with my approach or am I right in thinking that findradius will be slower? Haven't looked at engine code to see if findradius optimizes anything, but I'm just assuming it loops through all entities and checks for distance?
 Perhaps A Wash
#2221 posted by Preach [77.99.55.146] on 2016/10/18 20:36:27
I guess that findradius was written because the QC is significantly slower than checking all the entities by hand. On the other hand, I can't imagine that checking just one entity in QC is slower than calling the function, so there's a question of exactly when one becomes faster than the other.
If you're using the trick from
https://tomeofpreach.wordpress.com/2012/12/26/not-using-vlen/
then I'd guess the QC method is faster over 15 entities, but it'd be pretty close, so there's an argument to just using the simplest method and calling it a day.
#2222 posted by Spike [81.141.229.167] on 2016/10/18 21:46:09
if you're using fteqccgui, the 'annotate sourcecode' feature can be quite nice for showing you the actual instructions generated from each line of code.
combine that with what preach said, and then optimise it a bit more.
unlike engine code, qc code needs to write back each temporary to memory, it has to read each instruction, it has to do some jumps per instruction, it likely has extra bounds checks, etc.
the engine can just use hardcoded offsets etc, reads much less memory, has better cache performance, etc. on the other hand it does need to walk through every single entity...
so yes, its a tradeoff.
of course, if you're only doing it about 4 times per frame, then who gives a damn, just use the code that is the most maintainable.
#2223 posted by Kinn [86.131.180.211] on 2016/10/18 22:18:16
on the other hand it does need to walk through every single entity...
How are entities spatially partitioned in the bsp tree? Is there not a broad phase test?
#2224 posted by Spike [81.141.229.167] on 2016/10/18 22:57:06
findradius does not walk the bsp tree.
dp does use its areagrid for it which can be a speedup, but this does change behaviour, hence why its only dp that does that.
#2225 posted by Baker [72.168.129.178] on 2016/10/18 23:08:32
Can new FTEQCC with "extend an existing progs" be used to fix Marcher Fortress coop?
In coop for Marcher Fortress, unlike any other Quake SP release, if you grab silver/gold key they vanish because key_touch function sets model to none whether or not coop is set.
In theory, using the "fte mod an existing progs" you could add a new key_touch function to the old progs, but would need to override the old one.
#2226 posted by Kinn [86.131.180.211] on 2016/10/19 00:41:39
I introduced a retarded bug in marcher that buggers up coop in more than a few ways IIRC
I meant to release a patch, but it's 2016 now and I have other things eating up my time.... :{
 @baker
#2227 posted by Spike [81.141.229.167] on 2016/10/19 01:37:27
you *can* wrap the existing function, reverting the model back or whatever after the original touch function (or just replace it entirely), assuming you know the name of the function in question.
but its best to just harass Kinn for the source and fix it properly, or better yet harass him to provide a fix too, and then resort to function hijacks only if he's unable to do so.
extending existing progs is more useful in a general sense (like adding misc_model or trying to fix prevweapon stuff), or for mods whose source is completely unavailable.
you can use it for some really complex stuff, but the resulting code would likely be too hideous to work on long term.
 Randomised Textures
#2228 posted by Shamblernaut [121.45.233.149] on 2016/10/24 21:30:36
Pros and cons?
Because obvious repeating textures annoy the hell out of me, I've been thinking about how one might automate random textures on a face.
Here is the best implementation I can think of:
Modify qbsp to divide faces along a specified textures edges. Brushes containing that texture have their textures replaced with with another that has the same prefix and different number.
i.e. original texture is $0brick_wall, is replaced by $4brick_wall, etc.
It is an idea I'm playing with, and hell, I'll probably never implement it, regardless, what are your thoughts?
#2229 posted by Mugwump [80.215.156.215] on 2016/10/24 22:25:49
This could be interesting but IMHO only with slight variations of the same base texture, so as to avoid the grid effect. Any more than that and randomization will likely produce weird side effects.
#2230 posted by Pritchard [121.219.4.122] on 2016/10/25 01:20:49
I think one way to avoid repeating textures using that kind of compiler feature wou, rather than multiple textures for it to choose from, it could use one perfectly seamless texture and rotate it in random 90 degree intervals. Subtle but as far as I am aware a pretty effective result.
#2231 posted by Shamblernaut [121.45.233.149] on 2016/10/25 07:21:37
Yeah, but doesn't help with brick textures and such.
I had the realisation that this could also be implemented in editor. Which is probably the better option.
A third option (handy) but worst in my opinion, is decal support for quake maps. I think this is worst because it is engine specific, and the maps wouldn't be backward compatible.
#2232 posted by Pritchard [121.219.4.122] on 2016/10/25 07:35:12
Would it be though? If the decals were baked on during compilation they wouldn't be. But you'd have to make some pretty big changes to the compiler so that it was able to combine the appropriate images. It would be a pretty powerful tool though.
Psst, someone suggest it to ericw
#2233 posted by Shamblernaut [121.45.233.149] on 2016/10/25 07:43:46
the implementation required to make it work with vanilla would be really tricky, probably more complicated than its worth.
I think there is a maximum texture resolution, so if you were to decal over the edges of said texture, you can'd just make a huge mega-texture. In that case you would need to split the texture into separate parts to avoid that limitation.
Then it isn't just the one texture on the face anymore, so you need to split the geometry anyway.
#2234 posted by ericw [108.173.17.134] on 2016/10/25 08:38:30
I think the way to go for brick is to do what czg's honey does, make a 256x256 (I think?) version of a 64x64 texture.
also: http://www.celephais.net/stuff/texturefaq.htm
There is no upper limit to height or width that I know of. The largest texture that shipped with the game is 320x192.
#2235 posted by Shamblernaut [121.45.233.149] on 2016/10/25 10:13:51
well if it doesn't care about dimensions then I might make a little java app to randomise textures into a big texture then.
#2236 posted by Pritchard [121.219.4.122] on 2016/10/25 16:02:38
Well, for the record I'd still like to see decals someday >_>
I'm imagining it would get pretty whacky though. You'd have to account for the palette for instance when blending the two textures, I get the feeling that with some colours you'd end up having to make some compromises. And compromise is never something you really want to automate...
#2237 posted by Shamblernaut [121.45.233.149] on 2016/10/25 16:07:59
talk to mankrip re: colour blending with palettes, something tells me he's all over it.
#2238 posted by Pritchard [121.219.4.122] on 2016/10/25 16:14:01
That stuff freaks me out. Some kind of voodoo magic I think.
If he could provide ideas as to how his implementation could be applied to low-res textures that are baked into a map, I'm all ears, but from what I've seen a lot of the quality seems to rely on the fact that he's working with a high enough resolution that the grain introduced by the super duper advanced and spooky dithering isn't too obnoxious.
And by "I'm all ears", I mean "I hope someone else is all ears because I know enough about coding to know that I can't code that"
#2239 posted by Mugwump [80.215.206.244] on 2016/10/25 16:47:45
You'd have to account for the palette for instance when blending the two textures
Not if the decal is 24-bit, then it'll ignore the palette. One thing though: wouldn't decals exclude QS compat?
 Decals
#2240 posted by Qmaster [70.195.82.178] on 2016/10/25 19:24:04
Wouldn't be capable of using replacement textures, but I don't see why qbsp couldn't be extended to merge the decal with its underlying faces into a new texture. If qbsp then output these new textures with the names used such as <mapname>_dec1.pcx...<mapname>_decn.pcx then perhaps it could support replacement textures even if only manually.
#2241 posted by mukor [73.94.117.222] on 2016/11/26 16:52:26
Any help in solving this issue?
https://github.com/muk0r/qompiler/issues/1
Im building a compiler. I want it to use profiles to load saved compiling setting. How can I load a batch file to assign values to the variables I've created in the first batch file?
The current version is in branch v0.75
https://github.com/muk0r/qompiler/tree/Qompiler-v0.75
#2242 posted by Shamblernaut [121.45.238.31] on 2017/01/20 06:37:13
do any of you guys have access to the "team fortress" or "future vs fantasy" source codes?
#2243 posted by khreathor [78.88.31.219] on 2017/01/20 09:48:52
TF: http://upload.foppa.dk/files/tf_29src.zip
You should check out Custom TF too, cool stuff added there, like building your character. You could be a thief (invisibility). You could have a special knife and when you stabbed like 5 people you could summon a Shambler who was following and fighting for you! :D ...and other shit that people were adding over the years to their mods.
#2244 posted by khreathor [78.88.31.219] on 2017/01/20 09:55:08
Here you can read about some features: http://wiki.quakeworld.nu/Original_CustomTF_Version_File
You can find sources on SourceForge etc.
#2245 posted by Shamblernaut [121.45.238.31] on 2017/01/20 18:04:07
thanks man, much appreciated.
#2246 posted by Shamblernaut [121.45.238.31] on 2017/01/20 18:51:16
 BUMP.
#2248 posted by Shambler [88.111.202.28] on 2017/02/08 23:31:23
For people with coding issues.
 ^
#2249 posted by Blitz [66.171.190.42] on 2017/02/11 03:13:38
Was there already a long discussion at some point in the history of this board for why the Coding Help thread *shouldn't* be a permanent thread? Because it seems like it should be.
 Especially If It Avoids Half-arsed Toss Like This:
#2250 posted by Shambler [88.111.202.28] on 2017/02/12 20:37:30
QC Help [EDIT]
Posted by ijazz2 [125.17.68.26] on 2017/02/12 17:17:33
I am making a mod,but it wont compile.
I have spent one year making this plus correcting bugs,and on top of that school.So please,could someone help me? Fix fusion2.zip.
Quaketastic.com ,file in the QC Mistakes dir.
If anyone wants to use this then please put something like
modname/authorname_qc_date in DD/MM/YYYY .ZIP OR .7Z
THANK YOU,
-ijazz
Alos +1 vote for Quake Engines sticky, and Other PC Games thread sticky. Jury's out on CZG's Anus sticky but you can guess where my vote lies.
 FTEQCC Unwarranted Warnings.
#2251 posted by czg [213.113.209.223] on 2017/02/12 22:59:14
So I tried to clean up my qc a little bit and moved all the precaches in the worldspawn into its own function:
void worldspawn() =
{
(...)
precacheSounds();
precacheModels();
(...)
};
But now FTEQCC spams me with these warnings, even though it obviously works and these sounds are being precached:
player_movement.qc:80: warning F210: Sound "misc/water1.wav" was used but not precached
note: suppressed 12 more warnings about precaches.
Compile finished: ../progs.dat (id format)
Done. 22 warnings
Any way to get it to recognize that the precaches actually take place or disable this warning? I've already removed all other warnings from the source, so it'd be nice to have an actual clean compile for once.
This is in FTEQCC: Feb 11 2017
#2252 posted by Spike [86.145.136.139] on 2017/02/12 23:59:40
precache_sound() vs sound() calls go based upon string immediates that are passed in. if you're not using an immediate then fteqcc can't read/check it for you.
I guess you're looping through an array to precache your sounds (thus no immediates, so fteqcc can't see them), so either use the same lookup in your sound calls as in your precache_sound calls, or just '#pragma warning disable F210' to disable those warnings.
 Not Doing Anything That Fancy I'm Afraid.
#2253 posted by czg [213.113.209.223] on 2017/02/13 02:19:18
I just literally pulled all the precache calls from worldspawn out into a new method:
void precacheSounds() =
{
precacheSound ("misc/menu1.wav");
precacheSound ("misc/menu2.wav");
precacheSound ("misc/menu3.wav");
precacheSound ("misc/torchon2.wav");
precacheSound ("misc/spark.wav");
//and then ~200 more lines of the same...
I'll probably just disable the warning for now. It's easy enough to notice when you've forgotten to precache something.
 And By The Way
#2254 posted by czg [213.113.209.223] on 2017/02/13 02:26:52
Is there a list of all the pragmas and other interesting settings supported by fteqcc?
I've noticed you can actually do a whole lot of macro fuckery with it, which might turn out to be either really good or really bad...
 What Are You Working On?
#2255 posted by generic [66.87.123.4] on 2017/02/13 03:54:55
Hmmm...
 Fteqcc Info ...
#2256 posted by Baker [65.60.237.219] on 2017/02/13 05:37:08
 Other Fteqcc Info:
#2257 posted by Baker [65.60.237.219] on 2017/02/13 05:44:50
 This Is All Very Useful Info!
#2258 posted by czg [213.113.209.223] on 2017/02/13 09:22:51
Thanks!
 Useful Info Turns Out To Be Eldritch And A Gateway To Evil
#2259 posted by czg [213.113.209.223] on 2017/02/13 22:16:50
This is madness. I should not be doing this.
http://pastebin.ca/3767491
 Ugh
#2260 posted by Kinn [86.131.180.250] on 2017/02/13 23:27:08
Maths help please.
Given that:
1) I know the normal vector of a brush face.
2) I know the texture offset, scale and rotation on that brush face.
3) Quake's standard texture projection is being used (no fancy ETP stuff here, no sir)
How do I then calculate the width and height (in quake units) of a texture pixel as it appears projected on that brush face?
Why do I need to know this? Oh god, please don't ask :(
 Never Mind
#2261 posted by Kinn [86.131.180.250] on 2017/02/14 03:41:41
Hacked it in by raycasting from rotated and scaled texture coordinates along the direction of the projection axis onto the face plane and then measuring the distance between the points where the rays hit the plane.
If anyone's wondering, I was tested some retarded idea in Unity. Conclusion: idea was in fact retarded.
 Quake Mod With Deleted Enemies
#2262 posted by SpanishDiablo [81.33.22.49] on 2017/02/15 19:24:03
Dear Quake 1 community:
I'm looking for a SP mod for Quake 1 restoring the vomiting-tarbabies-Vomitus, the nailgun-ogre and the teleport-Vore/Wizard. I know you have very similar things in the community, but so far have been unable to identify them.
May you help?
Thank you!
#2263 posted by Shamblernaut [121.45.236.226] on 2017/02/16 05:39:12
I made a mod a while back which restored the ogre nail thing. The grenades are better, waaaay, better.
I'm not saying give up, I'm saying you'll probably be disappointed in that functionality.
 Non-Euclidean Geometry?
#2264 posted by charles the cat [98.216.249.17] on 2017/02/17 00:43:44
Do there exist mods that add worldportals? If not, how could they be implemented? My understanding of binary space partitioning suggests that this should be possible without wierd, hacky solutions like complicated dynamic camera/teleport setups.
 Generic Question
#2265 posted by czg [212.16.188.76] on 2017/02/21 12:46:25
Can you guys think of anything that's saved in a standard savegame that is specific to a player's preference?
The only thing I can think of is the player netname, which might not be something you care about in a singleplayer game.
Thinking about how feasible it is to include a savegame file with a map, for reasons
 @charles The Cat
#2266 posted by damage_inc [172.56.27.116] on 2017/02/21 13:20:38
I may not understand you correctly but...
Xonotic(Dark Places engine) has portals, and a member of Quake One, Nahuel I think, modified the QuakeC(progs.dat) for it to work in regular Quake(again DP only).
I have mapped with it and teleports are not used at all.
HTH's
 CZG
#2267 posted by Preach [82.46.16.57] on 2017/02/21 19:51:37
I did a map hacky thing which created a new adventure on e3m6 using a specially edited save game. As far as I know, nobody had any issues or any preferences overwritten by it.
PS: If you aren't combining this with the trigger_changelevel trick, then I sure will be sometime in the future...
 Statue Model
#2268 posted by madfox [84.84.178.104] on 2017/02/22 09:00:21
My attempt to convert my new model turned out wrong.
I took the code from soe.qc, deleted all new monster.qc and checked out the knight and hellknight. They both worked well.
Then I transcripted one of the two codes to my own model, but as result it wouldn't appear.
Is this statue code in someway assigned to these two monsters only,
or is my code messed up?
code
 #2268
#2269 posted by Spike [86.174.59.81] on 2017/02/22 11:18:49
surely that doesn't even compile...
 Well
#2270 posted by madfox [84.84.178.104] on 2017/02/22 21:04:33
it does, and it has a rather fancy skinn anim as the model in screenshots #14579 shows.
Why it is I don't know. I thought anim skin wasn't possible.
I think I screwed up the blrg.atk1 and balrog.atk names.
I thought the knight.qc and hknight.qc were ttached somewhere to the statue code only.
 Found It
#2271 posted by madfox [84.84.178.104] on 2017/02/23 00:02:58
missed semicolon.
 Angles_x Question
#2272 posted by gland [93.190.140.61] on 2017/02/27 00:46:03
Hi, please refer to this post where I describe a difference I found between how NetRadiant interprets angles versus how Quake 1 does (with regard to the orientation of models):
http://www.celephais.net/board/view_thread.php?id=61357&start=75
relevant image here:
http://i.imgur.com/KpBsWHB.png
I assume NetRadiant is geared up to conform to Quake 3's interpretation of angles. Is there a difference then between how Quake 1 and 3 do it - namely to do with angles_x being inverted?
#2273 posted by Spike [86.176.35.117] on 2017/02/27 01:58:25
inverted pitch angles is an 'unfixable' clientside bug that was present in the original software renderer, that was replicated in glquake and all quake engines since.
bsps and sprites pitch correctly - like in *Radiant, and mdls (and by extension md3+iqm - hurrah for consistent inconsistencies) pitch the wrong way.
makevectors uses 'proper' angles, but vectoangles is also affected by the bug.
it was fixed for hexen2 and quake2, but if you want to run quake mods properly then things must remain 'broken', especially if you want to join a public server.
probably the easiest way to deal with it is to create two separate entity types or something, then the mdl/md3/iqm version can just do self.angles_x *= -1.
there shouldn't be any other angle issues, just that one.
 Spike
#2274 posted by gland [93.190.140.61] on 2017/02/27 11:19:04
Thanks - very useful info.
#2275 posted by R00k [136.63.99.153] on 2017/02/28 02:37:26
"I just literally pulled all the precache calls from worldspawn out into a new method:
void precacheSounds() =
"
are you still calling precacheSounds() within worldspawn or else where?
 Calling It In Worldspawn Exactly Where The Precaches Were Originally.
#2276 posted by czg [213.113.209.223] on 2017/02/28 09:03:26
 Randomized Velocity In A Range
#2277 posted by Bloodshot [96.250.1.8] on 2017/03/01 03:31:21
Forgive me if this is more a general coding question but, is there a way to find a random number within a certain range? Like if I want a randomized x velocity from 150 to 300 for a gib
 Or Rather
#2278 posted by Bloodshot [96.250.1.8] on 2017/03/01 03:32:37
-150 to 300, sorry for not editing, forgot i had a login
 #2278
#2279 posted by Kinn [81.131.206.64] on 2017/03/01 03:41:20
(Random() * 450) - 150;
where Random() returns a random number from 0-1 - i assume QC has that?
 A Better Answer
#2280 posted by Kinn [81.131.206.64] on 2017/03/01 03:45:44
so yeah the general case for getting a random number between min and max is:
(random() * (max - min)) + min
where random() would be a builtin function returning a random number in the range 0-1
 Thank You
#2281 posted by Bloodshot [96.250.1.8] on 2017/03/01 04:01:56
How do i put a negative number in there? Like say i want a range from -250 to 250
#2282 posted by Kinn [81.131.206.64] on 2017/03/01 04:06:04
It's no different, "min" is -250, "max" is 250, so that would be
(random() * 500) - 250
 Thanks
#2283 posted by Bloodshot [96.250.1.8] on 2017/03/01 04:12:48
First time i did it with negatives i must've entered something wrong, now it's working thank you
 Any Way To Set Model Flags Through QC?
#2284 posted by Bloodshot [96.250.1.8] on 2017/03/01 06:14:58
Hexen 2 has some extra model flags for trails that I can't set unless I merge models with QME, but I still can't get exactly what I want
 @bloodshot
#2285 posted by Spike [86.176.35.117] on 2017/03/01 10:20:20
random:
random(-250, 400) will give you a random number between -250 and 400.
this will work with any HexenC compiler, as well as fteqcc even when not targetting hexen2.
model flags:
fte and dp both have some .float modelflags; field.
unfortunately the networking only supports the first 8 bits, and isn't supported by any (non-fte) hexen2 engines, so it won't get you anyhwere.
you may need to resort to a hex editor. you want the 32bit int at offset 0x4c.
although I'd like to think that later versions of qme allowed setting arbitrary flags...
 Good Point About QME
#2286 posted by Bloodshot [96.250.1.8] on 2017/03/01 23:03:18
I've been using 30 because I couldn't find the download again for 31, but I think I might be able to grab it from my laptop and check
#2287 posted by R00k [136.63.99.153] on 2017/03/02 04:48:50
i seem to have 3.1 ill look for a zip or i can make one i guess. I know i have it somewhere
#2288 posted by mukor [66.41.56.60] on 2017/03/02 04:52:45
#2289 posted by Pritchard [121.214.149.10] on 2017/03/02 11:24:59
It's been about 5 months since the last time this was asked, that's a pretty good run I guess. Maybe six next time? :p
 Can You Make Anonymous Functions In Qc?
#2290 posted by [172.98.67.111] on 2017/03/04 15:12:07
 Fteqcc
#2291 posted by Spike [86.176.35.117] on 2017/03/04 15:37:08
void() foo =
{
entity e = spawn();
e.think = (void()){
dprint("I THOUGHT!\n");
remove(self);
};
e.nextthink = time + 1;
};
such functions may still have undefined behaviour when it comes to saved games, especially when the progs itself is changed. so while you should probably still avoid it, the above works in most cases.
note that there's no enclosures - so you can't access the locals of the parent (static locals should work though).
 +1 Sticky This Thread
#2292 posted by Qmaster [70.195.70.196] on 2017/03/06 18:28:51
#2293 posted by Pritchard [121.214.149.10] on 2017/03/06 22:27:06
Make the thread sticky on its 10 year anniversary.
 Blood Splat Question
#2294 posted by Ruin [174.134.209.128] on 2017/03/08 06:11:31
Ok, I was in the wrong thread last time...
Do you know how to make a blood splat on the walls in quake that will align with the wall? I've seen it done before, but I cannot cite my sources, unfortunately. I'd be happy to pay someone to make a .qc file for this.
Thanks.
 Blood Splat Question
#2295 posted by Ruin [174.134.209.128] on 2017/03/08 06:11:37
Ok, I was in the wrong thread last time...
Do you know how to make a blood splat on the walls in quake that will align with the wall? I've seen it done before, but I cannot cite my sources, unfortunately. I'd be happy to pay someone to make a .qc file for this.
Thanks.
 Untested Suggestion
#2296 posted by Preach [82.46.16.57] on 2017/03/08 08:40:37
Try adding the following to SplatTouch above the line which changes self.velocity:
//fire a trace in the direction of movement to
//try and hit what we collided with
traceline(self.origin, self.origin + self.velocity, 0, world);
//if we hit a surface with the trace
//face the angle of the surface normal
if(trace_fraction < 1)
self.angles = vectoangles(trace_plane_normal);
It's ever so slightly hacky, because we need to try and reconstruct the collision. So we have a bit of logic to guard against failure, and we don't change the angle if it fails.
This code will fix the angle relative to the facing of the wall, but you may need to add a constant angle if it's consistently turned 90 degrees from true.
 Preach
#2297 posted by Ruin [174.134.209.128] on 2017/03/09 06:17:51
Preach, you brilliant bastard!
Can I compensate you for your help?
Thank you so much!
 Nah, Cheers
#2298 posted by Preach [82.46.16.57] on 2017/03/09 19:53:01
I'd risk getting a bit mercantile if I accepted that!
 Bit Subtraction
#2299 posted by R00k [107.188.184.100] on 2017/03/24 00:13:23
okay, I'm not a novice to QuakeC but, i have a question.
float FOO 64
float foo2 128
float foo3 256
so
is it incorrect to use:
value = value - FOO
vs
value = value - (value & FOO)
logically the first just subtracts 64.
I'm looking at OLD code and finding stuff like this.
I have always done it
value = value - (value & FOO);
to just turn off a value.
#2300 posted by Kinn [31.48.139.88] on 2017/03/24 00:22:36
is it incorrect to use:
value = value - FOO
I imagine you'll find instances of this in the old code only in places where they knew 100% that the bit was set, so just needed to subtract it.
Even so, it's still always better to use
value = value - (value & FOO)
because it shows the coder intent.
#2301 posted by Spike [86.176.70.105] on 2017/03/24 00:32:01
if you know that its already set then just subtracting it is fine...
 How Do I Get...
#2302 posted by ijazz2 [125.17.68.26] on 2017/03/26 09:12:12
After killing something,it drops a weapon,out of which some can be picked-up.Just like AD but with vanilla QC code.How do I get this?
I tried adding rubicon2's code for g_axe and g_shotgun in my mod but it didn't work.So now I am starting with a clean source in a few days,how do I make this code from scratch?
Is there a shortcut way to add frames for a monster in qc? I heard it was there in some tutorial online but I can't find it.
#2303 posted by khreathor [178.235.147.213] on 2017/03/26 10:00:24
Maybe start from checking out DropBackpack in items.qc
#2304 posted by R00k [136.63.99.153] on 2017/03/29 04:33:21
Like khreathor says,
when the mod drops a backpack, it spawns an entity, (with a timer to remove it).
To drop a gun seperate from the pack, like the gun in hand with *some* ammo, you need to spawn a new entity, with a PRECACHED model. and give that entity a .ammo amount, and create a touch function for that gun-entity.
I had done this once long ago. I will dig up some code and try to point you to your goal.
It only helps you to become a better coder with hints and not code cut/paste. But I can give you a detail list of what you need to get this working.
 Ijazz2
#2305 posted by Mike Woodham [109.148.167.181] on 2017/03/29 09:49:22
Not exactly what you want but you may find some of the coding useful to get what you are after:-
http://www.insideqc.com/qctut/qctut-60.shtml
http://www.insideqc.com/qctut/lesson-10.shtml
 Lightningdamage
#2306 posted by R00k [107.188.184.100] on 2017/03/30 20:12:43
does anyone know why IDsoftware made the trace for the lg start at the feet not +16?
```
org = self.origin + '0 0 16';
traceline (org, org + v_forward*600, TRUE, self);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);
LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
```
 Lightning Position
#2307 posted by Preach [82.46.16.57] on 2017/03/31 08:45:59
First thing to note is that the player's self.origin is at crotch level, not feet level. However, you are correct that the visual beam projects from a height of 16 units above the damage beam.
The sad truth is that the lightning bolt code is kinda buggy, and that's not even the worst bug. If you look through LightningDamage you'll notice it performs 3 traces in a row. The intent seems to be making the beam wider and allowing it to hit multiple enemies in the path. In fact, the vector calculations for the 2nd and 3rd are completely wrong, and the beams just fire into parts of the level that can't be seen by the player.
The buggy extra beams do fire in a way that is predictable based on the player's origin and facing angle. The following video shows a speedrun which exploits this! At about 50 seconds in, the player rides a lift down, faces in a very specific direction, and starts shooting the Thunderbolt. The specific location and direction of the shot causes a second beam to hit the Shalrath at the end of the level, which kills it before the doors open. This lets you grab the rune early, speeding up the run...
https://www.youtube.com/watch?v=D_P35WtpAwY
#2308 posted by onetruepurple [85.232.250.182] on 2017/03/31 09:42:05
origin is at crotch level
So that's realistic then.
 Lightning Buggy
#2309 posted by Qmaster [70.195.68.93] on 2017/04/01 00:33:46
Sounds like a fast 4 wheeler.
Anyhow, is there a fixed version of the code somewhere?
#2310 posted by ijazz2 [125.17.68.26] on 2017/04/05 14:55:30
I need to keep this thread at the top of the forum!
Someone please make this a permanent thread!
 @qmaster
#2311 posted by R00k [136.63.99.153] on 2017/04/08 06:27:20
org not origin
 Gpl License Rant
#2312 posted by komagama [151.16.48.217] on 2017/05/12 04:32:42
help guys:
I'm trying a Q1 total conversion(a true one! as Carmack stated in gpl readme) and I created my monsters totally re-skinning the standard knight model in qme.
So,in a supposed commercial release, may I use them also with the knight animations left untouched in qme ?
-my monsters don't resemble id original in any way and after all animations frames are only numeric values in qme not copyrighted assets I guess-
 Gpl
#2313 posted by Qmaster [67.45.40.52] on 2017/05/12 05:40:32
Lets you sell the stuff too.
 The Content Is No GPL
#2314 posted by No [204.17.56.42] on 2017/05/12 08:29:51
Engine and game code are GPL, the content is not. Even with a new skin, it's still the original model. You'd have to create a new one from scratch.
 ..thank But Think Of
#2315 posted by komagama [151.16.138.192] on 2017/05/12 13:33:13
..qc code:
qc code is free to use and from what I saw animation frames are also listed in it so what ?
 Semantics, Semantics
#2316 posted by Kinn [81.131.159.223] on 2017/05/12 14:12:41
When you say "skin" do you mean the texture or the model? At some point the word "skin" transitioned from originally meaning just texture to meaning the whole thing - texture AND model.
If your model is a completely new model built from scratch then I imagine it's fine in a commercial release.
 I Am Not A Lawyer! This Is Not Legal Advice!
#2317 posted by Spike [86.140.27.141] on 2017/05/12 21:01:52
'may I use them also with the knight animations left untouched in qme'
if you started with the knight model in qme, then the result is still a derivative work in some small way, and still subject to id's copyright.
strictly speaking such derivative works (note that this includes maps that just contain id's textures) should not be distributed at all, but we usually do so anyway on the understanding that the recipient has the full version of quake. I believe we follow that interpretation thanks to someone at id saying it'd be okay despite not being stated in the license, but I can't prove that sadly.
you may also be able to get by on fair-use laws, depending on legal jurisdictions... so you can probably get away with loading up the model and deleting the skins+verticies+triangles. names and sizes of frames+skins is probably okay under fair use, but sticking to those frame numbers means that your resulting model is probably going to play back at the wrong speed or something stupid/ugly like that, so its not something that's really worth much anyway.
the sources for the maps was also released (under the gpl) a while back, but combining that with the vanilla textures is arguably a violation of the gpl!
if you want a _total_ conversion, then delete pak0.pak and pak1.pak from your harddrive...
(and use a different palette... if only because quake's sucks...)
#2318 posted by khreathor [178.235.147.3] on 2017/05/12 23:57:12
I wonder what is minimum PAK content to run engine?
I guess palette, sprites to run MENU, start map, what else?
 Minimum
#2319 posted by Qmaster [67.45.40.52] on 2017/05/14 00:50:16
gfx.wad
Should be it I think.
#2320 posted by Spike [86.140.27.141] on 2017/05/14 07:31:49
dp+fte will both start up with absolutely nothing, depending on your definition of 'start'.
FTE:
for instance, if fte can't find id1/pak0.pak (or equivalent) then it'll not know what sort of game its meant to be running nor which gamedirs it should use. you can get it to behave with -basedir . -quake -nohome and it'll get the idea then. alternatively put fteqw.exe+default.fmf in the same dir and you can get the same effect without commandline args (possibly with other gamedirs instead, no id1).
if there's no [qw]progs.dat then fte will fail to spawn any entities. however, it will still load the world, the PutClientInServer function will fall back to spawning the player with noclip, and the various other missing functions will be ignored. The result is that you can at least view maps with nothing but the engine and a bsp... (and one of those 3 ways to get the filesystem code to be happy).
DP:
dp tends to have extra dll dependancies. I don't know if it'll cope without a progs.dat, but it should be fine if you give it a progs with just entity self;.float movetype;void()PutClientInServer={self.movetype=8;};
or you can just compile some gpled progs. obviously this isn't needed if you're just running it as a client.
QuakeSpasm/Other:
ignoring dll dependancies, other engines will definitely need some gfx.wad, for the palette lump, the colourmap(in sw renderers) lump, conchars lump, the various sbar image lumps (apparently quakespasm doesn't need those any more). They'll also need a gfx/conback.lmp, in most cases a gfx/pop.lmp (so they actually allow loading files without the demo's pak0.pak - this file can be generated correctly from the engine source which defeats the point of the check for it). annoyingly they'll also need a player.mdl (player baselines expect it, use a renamed spr or bsp if you want). any menus that are displayed (most noticeably the main menu) will need their images to load in order to avoid sys_errors.
you'll need a progs.dat if you're running it as a server. You'll need to provide everything up to end_sys_fields without reordering etc. this will also include a few functions which will need bodies, though they can be empty (you'll probably want at least the noclip thing though).
you'll also need a map, presumably.
those are the files/lumps that I can think of.
 I Confirm That Pak0 And Pak1 Are Needed..
#2321 posted by komagama [151.16.55.38] on 2017/05/14 13:40:59
..to run Quake, so better leave them there.
As for my TotalConversion project, do ya think a single person could bear all the load of work needed ?
I'm relatively good at creating textures, levels, models.. even weapons(aarrrgh!), but I fall short on fx sounds and AI code for example :(
AI is an intangible thing so how could people be aware if I use IDsoftware one ?
 Thanks Spike
#2322 posted by khreathor [178.235.147.3] on 2017/05/14 16:38:56
I found this thread about minimum code in QuakeC too: http://quakeone.com/forums/quake-talk/quake-central/11506-quakec-developer-tools.html
...but I think writing everything from scratch is kinda tedious task.
 AI Code In QuakeC
#2323 posted by Qmaster [70.195.86.190] on 2017/05/16 16:31:40
Quake's AI uses a set of think functions for various behaviours: th_run, th_stand, th_die,etc.
These functions start a chain of frame functions: void run1 [0] () { ai_run (<somedistance>)}, void run2, run3 etc.
Each function in the chain references a frame number in []'s.
The ai_run, ai_walk, ai_slide, etc. within each chain function moves the enemy by the set distance so that the monster can move realistically with its steps. For instance, at a frame where a foot touches the floor, you might not have an ai_run function or the ai_run will have a small value so the monster stops or slows with its steps.
Other functions do other actions timed with that frame in the animation.
Study the qc source for reference.
#2324 posted by [66.229.17.0] on 2017/06/01 01:38:45
Is there a documentation for the QuakeC opcodes? I'm planning to write a small compiler for something less crappy than QuakeC.
#2325 posted by Baker [65.60.237.219] on 2017/06/01 03:10:40
pr_comp.h in the Quake engine source code
 General Purpose Question
#2326 posted by dumptruck_ds [168.161.192.15] on 2017/06/01 19:22:48
I have a couple of Quake related utilities that were made for Win95 era. They won't run in compatibility mode in Windows 7. I know I have the source for at least one of them. They are very unique programs I was going to hand off to Quaddicted as they don't have them in the archives. One is a fractal terrain generator (FraQuake) and the other is a map editor that creates maps from simple text files (Phase II).
So the question is:
Is there a way to have these simply recompiled to work on modern OSes? Does something "automagic" like this exist? Or are their services that I could use to port these to run on modern OSes? I obviously know next to nothing about coding. I've never run a virtual machine either. I would assume there's a way to scratch the itch but love to hear options. VBRUN300.dll is required for both of them So I assume written in Visual Basic... errr maybe?
#2327 posted by Pritchard [124.180.138.22] on 2017/06/01 22:43:36
Generally speaking I find virtualization is the best way to keep using those tools. I use a win95 VM on my win10 machine for things like that (specifically, I set it up to run the QME installer).
Converting an app to run on modern windows otherwise would provably be a LOT of effort by comparison, unless perhaps the source code was already readily available...
 @pritchard
#2328 posted by dumptruck_ds [168.161.192.15] on 2017/06/01 23:44:32
Thanks, I am looking into installing Windows 7 32bit as I have a disk and license for that (note that it has 16 bit support whereas 64 bit versions don't). I have WinXP somewhere as well but lost my license. I know there are other options but I try to not "borrow" licences. ;)
I do have the source code for one of the the two proggies but in researching this it looks like VB3 is *really* freaking old and tough to find info on this stuff when you don't know what you are doing.
 You Could Include The Source
#2329 posted by Qmaster [70.195.65.145] on 2017/06/02 00:13:15
In your quaddicted upload. (Always and forever :) )
 @Qmaster
#2330 posted by dumptruck_ds [168.161.192.15] on 2017/06/02 00:54:16
Of course! I thought I had to email the files to Spirit. I can upload them? Will be happy to.
#2331 posted by Baker [65.60.237.219] on 2017/06/02 01:03:30
 Well
#2332 posted by Qmaster [70.195.65.145] on 2017/06/02 03:17:40
Ya you have to email them to spirit, but I mean please package them in the same zip beforehand and sounds cool. FraQuake? Whoa. Text mapping...hmmmm
 @Qmaster
#2333 posted by dumptruck_ds [68.119.139.87] on 2017/06/02 06:01:34
PhaseII is an oddity to be sure but both of these apps have a really interesting UI and are (to me) a pretty interesting part of our collective Quake lore. They were coded by a women who was injured in a car accident and kind of fell out of the Quake scene as a result. I've never been able to track down what happened to her after her hospitalization. I will email these to Spirit but here they are for the curious. No source for PhaseII unfortunately. Well worth a look IMO. That's why I wanted to get them running again.
https://www.dropbox.com/s/plh6rsopnx3c863/fraquake.zip?dl=0
https://www.dropbox.com/s/4hgvr5ojab38xnl/phase2.zip?dl=0
|