Another Quick One - Clear Screen
Is there a reliable way to clear the color buffer so that models can be rendered outside the level area?
I know about gl_clear but that doesn't do the trick here.
Here's some context: I want to move the player outside the level area and render a player select 'menu' with a couple of models in his line of sight. When he's made his choice, the player gets plopped back onto the spawnpoint.
This works fine in Quakespasm Spiked. FTE QW and Kex Quake render nothing at all when I move the viewpoint outside the level however.
Any ideas to get this working across engines?
Metlslime
#3073 posted by Shadow_Code on 2021/10/09 10:30:25
Yes, precaching of sounds alongside a dynamic element of gameplay was the problem. Thanks again, very glad to see that fixed.
Does anyone understand this (in id QC code)?
void() monster_xxx =
{
if (deathmatch) {remove(self);return;}
....
and on the other hand there is the bit "NOT IN DEATHMATCH" in the spawnflags of all entities,
processed by the engine at map start?
It seems as if Carmack doesn't trust map developers :)
#3076 posted by metlslime on 2022/01/28 21:54:13
Seems like a time-saver. Why make mappers do the manual labor of tagging every monster with the correct flag?
#3077 posted by metlslime on 2022/01/28 21:55:53
Also the "not in deathmatch" flag might have been added later, after this code was written.
Hurt_touch "fix" Issue
I tried to fix hurt_touch in triggers.qc according to the URQP. This is supposed to make every player in the entity getting hurt every second, not just the first one.
However, this code apparently makes Shub cause passive area damage on map END, which causes the Shambler (or player) standing next to it getting hurt.
Any idea what could be wrong here?
Original code:
void() hurt_on =
{
self.solid = SOLID_TRIGGER;
self.nextthink = -1;
};
void() hurt_touch =
{
if (other.takedamage)
{
self.solid = SOLID_NOT;
T_Damage (other, self, self, self.dmg);
self.think = hurt_on;
self.nextthink = time + 1;
}
return;
};
Changed code:
.float dmgtime;
.float attack_finished;
void() hurt_touch =
{
if (!other.takedamage)
return;
if ((time != self.dmgtime) && (time < self.attack_finished))
return;
T_Damage (other, self, self, self.dmg);
self.dmgtime = time;
self.attack_finished = time + 1;
};
Nightfright:
#3079 posted by metlslime on 2022/03/02 19:02:43
no idea, the code looks reasonable.
you could put some debug prints in the code to help with this.
For example, eprint(this) in hurt_touch and see if sometimes it's Shub.
If yes, see if somehow shub's self.touch is being set to hurt_touch
Thought At First
It might be port-related since QSS is acting kinda funky in its latest dev builds, but Shub is also screwed up in Ironwail and Mark V-WinQuake. I kinda based this on the way it's done in Lunaran's Copper mod, so I already suspected it couldn't be wrong. Unless my code simplifications f'ed something up...
I don't think I changed Shub code at all, but I'll take a look tomorrow. If it's not hurt_touch itself, it's something else.
If you wanna go ahead and check the entirety of the code, feel free to head over to the AMQ Github repository and get the QuakeC source. Maybe there's a connection I just can't see right now.
Eprint Test Done
When approaching Shub, I get console outputs with
Classname trigger_hurt
Touch hurt_touch()
Shub's code looks like this in monster_oldone:
[...]
self.takedamage = DAMAGE_YES;
self.th_pain = (void(entity,float)) nopain;
self.th_die = finale_1;
self.touch = monster_touch;
shub = self;
The self.touch part is another fix that is supposed to prevent sliding/not-jumping on top of monsters. Might that have something to do with it?
Trigger_hurt
#3082 posted by Preach on 2022/03/03 08:33:56
I have a suspicion that END secretly relies on the bug you've just fixed. There's a 16 unit high trigger_hurt spanning the width of shub's platform, at about eye level. I'm guessing that prior to the fix, most of the time shub is absorbing the damage, which has no observable effect. You do occasionally get a 10 hp tic of damage when you jump on the island.
Could Be
Well, now you get the 10 HP tic all the time, it seems. Besides undoing the fix (which would be the least ideal solution), is there maybe some kind of exception that could be included to preserve the original behavior, at least on that specific map? I doubt it would matter elsewhere (even though you can never be sure).
This Seems To Do The Trick
void() hurt_touch =
{
if (!other.takedamage)
return;
if ((time != self.dmgtime) && (time < self.attack_finished))
return;
if (world.model == "maps/end.bsp")
{
self.solid = SOLID_NOT;
T_Damage (other, self, self, self.dmg);
self.think = hurt_on;
self.nextthink = time + 1;
}
else
{
T_Damage (other, self, self, self.dmg);
self.dmgtime = time;
self.attack_finished = time + 1;
}
};
-----------------
Basically what I am doing here is to use the old code only on the "end" map. I don't know if this is efficient programming or whether it can be done in a more elegant way, but it's working.
+use Alternative
#3085 posted by UnknownDud3 on 2022/04/22 00:15:27
Hey. I don't know much about quake modding yet but I am already curious if it's possible to implement a doom-like use command/key to interact with buttons, doors etc. Maybe there might be an example of such functionality?
@UnknownDud3
#3086 posted by metlslime on 2022/04/22 04:20:52
There is evidence in the code that they once had a use button, for example, there is a +use command that is defined in the engine code, and there is a ".float button1; //use" in the quakec source. But, the network protocol never sends or reads that data so it's not usable.
However, you can easily define your own use button -- the impulse system lets a mod define a large number of arbitrary inputs that the user can bind to keys and the quakec code can read and use. So you'd just have to bind a key to e.g. "impulse 50", then in your quakec code you can do whatever you want with that. Look in weapons.qc at the function "ImpulseCommands" for examples.
(also note, that you can put impulse checks for self.impulse in any place in your quakec code as long as it's in a function where "self" is expected to be a player.)
One final caveat, there can only be one "impulse" per frame so the player won't be able to both "switch weapons" and "use the door" on the same frame, one of those inputs will be ignored.
@metlslime
#3087 posted by UnknownDud3 on 2022/04/22 10:57:43
Thank you for the given information, I really appreciate your help! Though I still require any example (if one exists) where the use functionality is implemented as I can't figure it myself yet :(
About Use Again
#3088 posted by UnknownDud3 on 2022/04/22 16:48:40
I've looked through the qc files and found there are even functions for the use thing in buttons and doors code, but I can't get it what exactly has to be done to call them...
@UnknownDud3
#3089 posted by metlslime on 2022/04/22 18:46:41
When you see SUB_UseTargets in quakec, that is a different meaning of "use" than you're thinking. That's how various entities can trigger each other (e.g. when I pick up a key, it teleports some enemies. When I press a button, it opens a door.) Not the same concept as what you're looking for.
QuakeC String Hash
#3091 posted by ephemeris on 2023/01/10 04:56:55
TLDR is there a way to loop through string chars?
I am trying to implement a feature that requires passing a string through a level change. Specificly I want to preserve the last map the player was on so that I can pick the correct info_player_start. I found that the only string that persists across level changes is the username. I was able to get the feature to work by changing the user name to the current map then use this to match the correct info_player_start map field on the far side. For several reasons this solution sucks, now I want to compute a simple hash of the map name stuff that into a spawn param then compare that to hashes of the map field in player_start. How do I access individual chars in a string? reading the docs: string[index] does not look like it would work.
Ephemeris:
#3092 posted by metlslime on 2023/01/13 00:46:07
I don't think you can really do anything with strings in standard quakec. However, you should be able to accomplish your goal using numeric values instead.
Idea 1: the hacky way, hard-coding map names into quakec. You can check the worldmodel to see which map it is, set a value, then read it on the next map load. This is is how there is low gravity in e1m8
if (self.model == "maps/e1m8.bsp")
cvar_set ("some_unused_cvar", "1");
else
...
Idea 2: you can set a numeric property on the trigger_changelevel of each map, grab that value in quakec and set some variable to read when you get back to the start map. Then set the same unique values on the info_player_starts in your startmap. This is cleaner because all the special values live in map files not in your code.
More On Quake Strings.
#3093 posted by ephemeris on 2023/01/14 15:06:20
I suspect you are correct, I wanted to avoid the hard coded number field, it would work, but I had my heart set on using the map name.
As I find more and more docs, I am learning more than I ever wanted to know about quakec. fteqcc can index a string( string[index] ) but it requires a pragma target fte. and now nether DP nor quakespasm want to load the resultant progs.dat. I could probably go with fte and call it a day but I want to avoid limiting myself like that. Now I am trying to figure out what extensions darkplaces supports and there is a substr() function. this may work, No idea if can cast the result to a float(I suspect not). but that is my next attempt.
salutes and thanks for the encouraging words.
Euler Angles
#3094 posted by crystallize on 2023/01/23 20:19:25
How to calculate roll from a vector? I tried and atan2(-y, x) was best so far but roll can still jump from 162 to 77 when moving in loop-de-loop.
#3095 posted by metlslime on 2023/01/23 23:57:26
I don't think you can really get that. A single vector representing a forward direction doesn't have an inherent roll to it.
#3094
#3096 posted by Spoike on 2023/02/11 21:51:47
A number of engines have a two-arg version of vectoangles, the second being the 'upwards' vector that pairs with the regular 'forward' vector arg. It doesn't need to be fully perpendicular - its sole use is for computing the proper resulting roll angle.
You can then use makevectors twice, do some matrix maths to combine them (hurrah for order mattering), and then vectoangles2 to get back to eular angles.
vectoangles' buggy pitch values are still an issue though (along with mdl pitch too). just flip the sign as appropriate depending on bsp/spr/view/makevectors vs mdl/vectoangles.
|