Host_Error: PRVM_Execute Program
Moderator: InsideQC Admins
8 posts
• Page 1 of 1
Host_Error: PRVM_Execute Program
I have a new enemy coded in and it works great as long as you kill him in one hit. If he takes damage of any kind and he doesn't die quake (darkplaces) crashes with "Host_Error: PRVM_Execute Program: QC Function self.think is missing. Now it is clear what is wrong, or is it? I checked the whole new monster qc and all the nextthinks have thinks and everything matches up well. If it helps fitzkurok said "Host_Error: PR_Execute Program: Null function" What would cause this? I'll post code if i need to.
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
The only thing I can imagine causing the error is exactly what's stated in the message: it's very likely that in one of the frames of the death sequence you're setting self.nextthink = time + something with self.think not initialized correctly. Without seeing the code itself it's hard to tell, though.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC
(LordHavoc)
-

frag.machine - Posts: 2090
- Joined: Sat Nov 25, 2006 1:49 pm
- Code: Select all
/*
barnacle.qc
*/
void() barnacle_check;
void() barnacle_touch;
void() barnacle_push =
{
if (self.t_width <= time)
{
if (self.walkframe >= 51)
self.walkframe = 0;
self.frame = 0 + self.walkframe;
self.walkframe = self.walkframe + 1;
self.t_width = time + 0.03;
}
if (self.enemy.health <= 0)
{
barnacle_check ();
self.touch = barnacle_touch;
return;
}
if (self.enemy.flags & FL_ONGROUND)
self.enemy.flags = self.enemy.flags - FL_ONGROUND;
self.enemy.velocity = '0 0 50';
self.enemy.origin_x = self.origin_x;
self.enemy.origin_y = self.origin_y;
self.nextthink = time;
self.think = barnacle_push;
};
void() barnacle_check =
{
self.nextthink = time;
self.think = barnacle_check;
self.frame = 0;
traceline (self.origin, self.origin - '0 0 1000', FALSE, self);
if (trace_fraction == 1.0)
return;
if (trace_ent.takedamage == DAMAGE_AIM)
{
self.enemy = trace_ent;
sound (self, CHAN_VOICE, "barnacle/alert2.wav", 1, ATTN_NORM);
self.walkframe=0;
barnacle_push ();
}
};
void() barnacle_bite =
{
if (self.t_width <= time)
{
if (self.walkframe >= 61)
{
self.walkframe = 0;
if (random() < 0.3)
sound (self, CHAN_BODY, "barnacle/chew1.wav", 1, ATTN_NORM);
else if (random() < 0.6)
sound (self, CHAN_BODY, "barnacle/chew2.wav", 1, ATTN_NORM);
else
sound (self, CHAN_BODY, "barnacle/chew3.wav", 1, ATTN_NORM);
T_Damage (self.enemy, self, self, 60);
if (self.enemy.health <= 0)
{
barnacle_check ();
self.touch = barnacle_touch;
return;
}
}
self.frame = 51 + self.walkframe;
self.walkframe = self.walkframe + 1;
self.t_width = time + 0.03;
}
self.enemy.velocity = '0 0 50';
self.enemy.origin_x = self.origin_x;
self.enemy.origin_y = self.origin_y;
self.nextthink = time;
self.think = barnacle_bite;
};
void() barnacle_die_go = [112, barnacle_die_go]
{
if (self.walkframe >= 100)
self.walkframe = 100;
self.frame = self.frame + self.walkframe;
self.walkframe = self.walkframe + 1;
self.nextthink = time + 0.03;
self.think = barnacle_die_go;
};
void() throw_gibs =
{
self.nextthink = time;
self.think = throw_gibs;
if (self.health < time)
{
remove(self);
return;
}
if (self.attack_finished < time)
{
if (random() < 0.3)
ThrowGib ("progs/gib1.mdl", 0);
else if (random() < 0.6)
ThrowGib ("progs/gib2.mdl", 0);
else
ThrowGib ("progs/gib3.mdl", 0);
self.attack_finished = time + 0.15 + random()*0.2;
}
};
void() barnacle_die =
{
local entity o;
self.solid = SOLID_NOT;
if (random() < 0.5)
sound (self, CHAN_VOICE, "barnacle/die1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "barnacle/die3.wav", 1, ATTN_NORM);
o = spawn ();
o.origin = self.origin;
o.health = time + 2;
o.nextthink = time;
o.think = throw_gibs;
remove(self.owner);
self.walkframe=0;
self.nextthink = time + 0.1;
self.think = barnacle_die_go;
};
void() barnacle_touch =
{
if (other.takedamage == DAMAGE_AIM)
{
self.walkframe=0;
barnacle_bite ();
sound (self, CHAN_BODY, "barnacle/bite3.wav", 1, ATTN_NORM);
self.touch = SUB_Null;
}
};
void() ParseTongue =
{
local entity tongue;
local float tracedist, tsize;
traceline (self.origin, self.origin - '0 0 1000', FALSE, self);
tracedist = 1000*trace_fraction;
while (tsize < tracedist)
{
tsize = tsize + 32;
tongue = spawn ();
tongue.origin = self.origin;
tongue.origin_z = tongue.origin_z - tsize;
tongue.nextthink = time + 0.2;
tongue.think = SUB_Remove;
setmodel (tongue, "progs/tongue.mdl");
}
};
void() tongue_think =
{
self.nextthink = time + 0.2;
self.think = tongue_think;
ParseTongue ();
};
void() monster_barnacle =
{
local entity o;
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/barnacle.mdl");
precache_model ("progs/tongue.mdl");
precache_sound ("barnacle/alert2.wav");
precache_sound ("barnacle/bite3.wav");
precache_sound ("barnacle/chew1.wav");
precache_sound ("barnacle/chew2.wav");
precache_sound ("barnacle/chew3.wav");
precache_sound ("barnacle/die1.wav");
precache_sound ("barnacle/die3.wav");
self.solid = SOLID_SLIDEBOX;
self.flags = FL_MONSTER;
setmodel (self, "progs/barnacle.mdl");
setsize (self, '-16 -16 -32', '16 16 0');
self.health = 35;
self.takedamage = DAMAGE_AIM;
self.th_die = barnacle_die;
self.th_stand = barnacle_check;
self.nextthink = time + 0.1 + random()*0.5;
self.think = barnacle_check;
self.touch = barnacle_touch;
total_monsters = total_monsters + 1;
self.owner = spawn ();
o = self.owner;
o.origin = self.origin;
o.nextthink = time + 0.2;
o.think = tongue_think;
setmodel (o, "progs/tongue.mdl");
};
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
My guess is that you have FL_MONSTER flag set but no th_run. When you shoot the barnacle, T_Damage is called. Near the bottom of that function, it calls FoundTarget() if the target is FL_MONSTER. FoundTarget calls HuntTarget, which sets self.think to self.th_run.
You should remove the FL_MONSTER flag, or else add an extra check to return from that code path if classname is "barnacle". (IIRC you might want to keep FL_MONSTER for other reasons, for example the enlarged bbox for opposing traces?)
Or you could add a th_pain, since self.th_pain (if it isn't null) is called after FoundTarget. But your previous think function would still be getting overridden, which might mess up your specialized monster behaviour.
You should remove the FL_MONSTER flag, or else add an extra check to return from that code path if classname is "barnacle". (IIRC you might want to keep FL_MONSTER for other reasons, for example the enlarged bbox for opposing traces?)
Or you could add a th_pain, since self.th_pain (if it isn't null) is called after FoundTarget. But your previous think function would still be getting overridden, which might mess up your specialized monster behaviour.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
- Sajt
- Posts: 1215
- Joined: Sat Oct 16, 2004 3:39 am
I tried both, either/or and at the same time. Still nothing. If it helps to narrow it down, when it is "sucking you up" you can shoot it and its fine, but if its just chillin there and you shoot it and you dont kill it it crashes.
EDIT: I got it now, I did it RIGHT thanks Sajt
EDIT: I got it now, I did it RIGHT thanks Sajt
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
Sajt wrote:My guess is that you have FL_MONSTER flag set but no th_run. When you shoot the barnacle, T_Damage is called. Near the bottom of that function, it calls FoundTarget() if the target is FL_MONSTER. FoundTarget calls HuntTarget, which sets self.think to self.th_run.
You should remove the FL_MONSTER flag, or else add an extra check to return from that code path if classname is "barnacle". (IIRC you might want to keep FL_MONSTER for other reasons, for example the enlarged bbox for opposing traces?)
Or you could add a th_pain, since self.th_pain (if it isn't null) is called after FoundTarget. But your previous think function would still be getting overridden, which might mess up your specialized monster behaviour.
But the reported error was in self.think, not self.th_run (which AFAIK is not mandatory). Even if it was required, one could just set th_run = SUB_Null and everything should work with FL_MONSTER set.
EDIT: I think there's something wrong with this piece of code:
- Code: Select all
void() barnacle_die_go = [112, barnacle_die_go]
{
if (self.walkframe >= 100)
self.walkframe = 100;
self.frame = self.frame + self.walkframe;
self.walkframe = self.walkframe + 1;
self.nextthink = time + 0.03;
self.think = barnacle_die_go;
};
You could/should remove the "[112, barnacle_die_go]" part, since you're doing all the animation by hand.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC
(LordHavoc)
-

frag.machine - Posts: 2090
- Joined: Sat Nov 25, 2006 1:49 pm
frag.machine wrote:But the reported error was in self.think, not self.th_run (which AFAIK is not mandatory). Even if it was required, one could just set th_run = SUB_Null and everything should work with FL_MONSTER set.
It's reporting "think" being null because HuntTarget sets self.think to self.th_run and sets nextthink, it doesn't call th_run directly.
You could add th_run (or th_pain) for the monster, but like I said it would still end up overriding the previous think, which might screw up his special monster behaviour (or it might not, I don't know).
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
- Sajt
- Posts: 1215
- Joined: Sat Oct 16, 2004 3:39 am
well what I did was make the th_walk, th_run, th_pain, etc just do barnacle_check and it seemed to work just fine. I'm pretty sure that was the issue since it had no th_XXXX other than th_die and and th_stand.
Thanks for the help guys!
AI, for some reason, I just can't get the hang of and it irritates me.
Thanks for the help guys!
AI, for some reason, I just can't get the hang of and it irritates me.
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
8 posts
• Page 1 of 1
Return to Artificial Intelligence
Who is online
Users browsing this forum: No registered users and 1 guest