Got A Tricky One
#1493 posted by ijed 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 on 2014/07/23 15:39:04
Stupid mistake in walkmonster_start
#1495 posted by digs on 2014/07/28 10:48:19
Can I make a recursive function? What is the maximum stack depth?
Recursion
#1496 posted by Preach 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 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 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 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 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 on 2014/07/29 01:47:48
I thought it was 100000 instructions per frame.
Reset The Counter
#1502 posted by Preach 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 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 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 on 2014/07/30 22:31:36
#1506 posted by metlslime on 2014/07/30 22:37:50
probably darkplaces has this.
Darkplace Does
#1507 posted by Preach 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 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 on 2014/07/30 23:56:19
float(vector targ_origin) check_pointcontent =
{
����return (pointcontents(targ_origin) == CONTENT_SKY);
}
@Preach
#1510 posted by sock 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 on 2014/07/31 00:29:41
nt
Cool
#1512 posted by Qmaster on 2014/07/31 01:32:59
As ever yall are awesome. Thank you!
Okay Then.
#1513 posted by Qmaster 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 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 on 2014/07/31 16:32:53
Its like a treasure hunt!
Question On QC Syntax
#1516 posted by Preach 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 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.
|