News | Forum | People | FAQ | Links | Search | Register | Log in
Coding Help
This is a counterpart to the "Mapping Help" thread. If you need help with QuakeC coding, or questions about how to do some engine modification, this is the place for you! We've got a few coders here on the forum and hopefully someone knows the answer.
First | Previous | Next | Last
Private Spoon 
Sorry for the Malice progs.dat
Even when the ones that created feel sorry now for their encriptment. 
Kinn 
I sent Preach an email about that subject yesterday evening. I'm waiting for his response. 
Compiler 
What QC Compiler would you recommend nowadays? 
Fteqcc 
 
I think it's the only modern one..? 
Don't Call It Monsterclip... 
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... 
 
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... 
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. 
 
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 
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 
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 
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? 
 
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. 
 
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 
It's the same principle, but without the switch/case cascades. 
Re: Tempstrings 
@ 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 
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 
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? 
 
No clue about quakec but

1) gatlingsound = TRUE surely would be an assignmen, not a comparison?

2) float as Boolean?! 
 
Went looking for an equivalent in the quakeC manual, it said "float" was it.

Or maybe I misred it and it's something else? 
 
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. 
 
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 
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 
Your thing got compiled. Thanks! 
@Lunaran 
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. 
First | Previous | Next | Last
You must be logged in to post in this thread.
Website copyright © 2002-2024 John Fitzgibbons. All posts are copyright their respective authors.