I've start re-writing my quake mod from the ground up but I've ran into a problem. I made some code to randomize a location and spawn an enemy in that location, tested with the use of a button press for now. That part of it works perfectly, but the problem is, is when it is applied to the scrag/wizard.qc the game freezes for about 10 seconds then dumps me to the console.
For all walking monsters I've been calling walkmonster_start_go(); (that works great). Using that also works for the scrag, but it doesn't function as a flying monster.
So I attempt to use flymonster_start_go(); Which is no different to walkmonster apart that it contains 2 small difference (no droptofloor() and the additional self.flags = self.flags | FL_FLY;). But I get a crash.
Though I have isolated that self.flags = self.flags | FL_FLY; within flymonster_start_go is causing the crash, I don't know why.
Help with a small problem.
-
- InsideQC Staff
- Posts: 1120
- Joined: Sat Oct 16, 2004 3:34 pm
-
- Posts: 6
- Joined: Mon Aug 08, 2011 9:08 pm
-
- InsideQC Staff
- Posts: 1120
- Joined: Sat Oct 16, 2004 3:34 pm
Re: Help with a small problem.
Looks like you're getting some kind of runaway loop spawning entities. I'll need to see what your spawning code is doing.
EDIT:
Another thing to look at is whether you're precaching stuff at any time other than mapload. (The exception to this is the Hipnotic spawner method.) Some engines will forgive you when you do this (DP, FTE), most others WILL get upset if you try to precache midgame.
EDIT:
Another thing to look at is whether you're precaching stuff at any time other than mapload. (The exception to this is the Hipnotic spawner method.) Some engines will forgive you when you do this (DP, FTE), most others WILL get upset if you try to precache midgame.
Re: Help with a small problem.
Check the ticrate too and make sure nothing is thinking faster than it, otherwise I believe that can cause sv_getspace overflow as well as spawn alot of entities depending on the code.
-
- Posts: 6
- Joined: Mon Aug 08, 2011 9:08 pm
Re: Help with a small problem.
On one button press it will either be 1 monster that spawns or none at all (I know this because it works perfectly with all the other monsters).
Code: Select all
void() monspawn_wizard =
{
local entity temp;
local float posneg;
local float attempt;
posneg = random();
precache_model ("progs/wizard.mdl");
precache_model ("progs/h_wizard.mdl");
precache_model ("progs/w_spike.mdl");
precache_sound ("wizard/hit.wav");
precache_sound ("wizard/wattack.wav");
precache_sound ("wizard/wdeath.wav");
precache_sound ("wizard/widle1.wav");
precache_sound ("wizard/widle2.wav");
precache_sound ("wizard/wpain.wav");
precache_sound ("wizard/wsight.wav");
//START SPAWN
while (attempt <=100) //OVERFLOW PREVENTION
{
temp = self;
self = spawn ();
if (posneg >= 0.0 && posneg < 0.5)
{
self.origin_x = random() * 4096; //RANDOM THINGYS (NOT SURE IF THE WHOLE RANGE IS COVERED)
self.origin_y = random() * 4096;
self.origin_z = random() * 4096;
}
if (posneg >= 0.5 && posneg <= 1.0)
{
self.origin_x = random() * -4096;
self.origin_y = random() * -4096;
self.origin_z = random() * -4096;
}
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, "progs/wizard.mdl");
setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX);
self.health = 80;
self.classname = "monster_wizard";
self.th_stand = wiz_stand1;
self.th_walk = wiz_walk1;
self.th_run = wiz_run1;
self.th_missile = Wiz_Missile;
self.th_pain = Wiz_Pain;
self.th_die = wiz_die;
flymonster_start_go();// self.flags = self.flags | FL_SWIM; causing the crash.
//walkmonster_start_go();//OK! but not a fly monster anymore
bprint("a scrag joins the game\n");
if (!walkmove(0,0))
{
attempt = attempt + 1;
bprint("DAVEBUG: TRYING AGAIN\n");
remove(self);
monspawn_wizard();//SHOULDN'T REALLY BE DOING THIS, BUT SEEMS TO WORK AS LONG AS I LIMIT IT.
return;
}
if (walkmove(0,0))
{
bprint("DAVEBUG: PLUS 1\n");
total_monsters = total_monsters + 1;
}
}
self = temp;
}
-
- InsideQC Staff
- Posts: 1120
- Joined: Sat Oct 16, 2004 3:34 pm
Re: Help with a small problem.
Yeek, and Egad. No offense, but there is just SO MUCH wrong with that code...
I'll start with what's causing the crash first:
You are attempting to break out of a loop by doing this, and causing all kinds of evile in the process:
Bad, bad, bad. attempt will NEVER reach 100 like this, thus infinite loop, thus crash to console.
Try this instead:
That doesn't address all the problems I have with the code, but it should get you up and running.
If it works, but doesn't spawn any monsters...you might have to set self.flags = self.flags | FL_FLY; before running the while loop, flying and swimming monsters are odd this way.
I'll start with what's causing the crash first:
You are attempting to break out of a loop by doing this, and causing all kinds of evile in the process:
Code: Select all
if (!walkmove(0,0))
{
attempt = attempt + 1;
bprint("DAVEBUG: TRYING AGAIN\n");
remove(self);
monspawn_wizard();//SHOULDN'T REALLY BE DOING THIS, BUT SEEMS TO WORK AS LONG AS I LIMIT IT.
return;
}
Try this instead:
Code: Select all
void() monspawn_wizard =
{
local entity temp;
local float posneg;
local float attempt, success; // DRS: for 100 attempt failure check later
posneg = random();
precache_model ("progs/wizard.mdl");
precache_model ("progs/h_wizard.mdl");
precache_model ("progs/w_spike.mdl");
precache_sound ("wizard/hit.wav");
precache_sound ("wizard/wattack.wav");
precache_sound ("wizard/wdeath.wav");
precache_sound ("wizard/widle1.wav");
precache_sound ("wizard/widle2.wav");
precache_sound ("wizard/wpain.wav");
precache_sound ("wizard/wsight.wav");
//START SPAWN
// DRS: set up the monster most of the way first.
temp = self;
self = spawn ();
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, "progs/wizard.mdl");
setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX);
self.health = 80;
self.classname = "monster_wizard";
self.th_stand = wiz_stand1;
self.th_walk = wiz_walk1;
self.th_run = wiz_run1;
self.th_missile = Wiz_Missile;
self.th_pain = Wiz_Pain;
self.th_die = wiz_die;
while (attempt <=100) //OVERFLOW PREVENTION
{
if (posneg >= 0.0 && posneg < 0.5)
{
self.origin_x = random() * 4096; //RANDOM THINGYS (NOT SURE IF THE WHOLE RANGE IS COVERED)
self.origin_y = random() * 4096;
self.origin_z = random() * 4096;
}
if (posneg >= 0.5 && posneg <= 1.0)
{
self.origin_x = random() * -4096;
self.origin_y = random() * -4096;
self.origin_z = random() * -4096;
}
//DRS: Good idea to use setorigin.
setorigin(self, self.origin);
if (!walkmove(0,0))
{
attempt = attempt + 1;
bprint("DAVEBUG: TRYING AGAIN\n");
}
else
{
bprint("DAVEBUG: PLUS 1\n");
total_monsters = total_monsters + 1;
// DRS: Break out of while loop.
attempt = 100;
success = TRUE; // DRS: SUCCESS!
}
}
// DRS: check for success
if(success == FALSE)
{
bprint("DRS NOTIFY: random monster location failed\n");
remove(self);
return;
}
// DRS: Successful location found, finish setting up monster.
flymonster_start_go();// self.flags = self.flags | FL_SWIM; causing the crash.
//walkmonster_start_go();//OK! but not a fly monster anymore
bprint("a scrag joins the game\n");
self = temp;
}
If it works, but doesn't spawn any monsters...you might have to set self.flags = self.flags | FL_FLY; before running the while loop, flying and swimming monsters are odd this way.
-
- Posts: 6
- Joined: Mon Aug 08, 2011 9:08 pm
Re: Help with a small problem.
No offence taken at all, it's all a learning process. (I'm fairly noobish at coding in general, plus my friend has already gave me a lecture about how much is wrong with this code hahah.). Thanks a lot for this, it will help me clean up my other spawner's up a little as-well. (Well I suppose this is what I get for having a large ambition with crappy coding skills lol)
Re: Help with a small problem.
one programming guideline is to take the view that more than one return from a function is poor design.
the idea being something along the lines of:
essentually, the idea is to cascade out of the function on either success or error. this keeps the two cases equivelent to each other and avoids bugs arising within the error cases (within the function itself, but not the caller) .
the creates and releases synced across the top and the bottom of the block. much of the work to do with freeing anything you allocated becomes mechanical rather than anything you actually need to think about.
in qc terms, 'release' is the act of restoring a global to the value it originally was. yay globals!...
the idea being something along the lines of:
Code: Select all
entity ret = world;
a = createobject();
if (a)
{
b = createobjectfrom(a);
if (b)
{
ret = createobjectfrom(b);
}
releaseobject(b);
}
releaseobject(a);
return ret;
the creates and releases synced across the top and the bottom of the block. much of the work to do with freeing anything you allocated becomes mechanical rather than anything you actually need to think about.
in qc terms, 'release' is the act of restoring a global to the value it originally was. yay globals!...