
Tutorial: Incorporating Non Interactive, Non Playable Characters (NINPC’s)

Level: Easy
Author: Ninja of Comp
Well, Curious George had mentioned that he’d like to incorporate NPC’s in his mod. You know, characters that are there but are not the enemy and you can either interact with them or there just there to look pretty. Well I’m going to show you how to create the non-interactive NPC’s (or NINPC’s for short).
Remember the Easterchick & EasterTank? Those are NINPC’s. the easterchick just sits there TRYING to look pretty and the eastertank just….uh….sits there. You can’t kill them and they care less what you do.
Well, why does it have to be just them two? Why can’t I have a blacksmith, a bartender, maybee some drunk dude in the corner or begger on the streets. There are two ways to create these NONPC’s. One is to create a separate entity in your leveleditor that you can put in your levels, create the model, and add the code. But I don’t know how to add a new entity to my level editor (yet). So the second method is to use the same easterchick entity and code to create any NINPC you want.
Note: I use the QOOLE level editor and LCC for the compiler.
Open g_misc.c and locate misc_easterchick_think procedure and change this:
void misc_easterchick_think (edict_t *self)
{
if (++self->s.frame
< 247)
self->nextthink
= level.time + FRAMETIME;
else
{
self->s.frame
= 208;
self->nextthink
= level.time + FRAMETIME;
}
}
to the following:
void misc_easterchick_think (edict_t *self)
{
// **************************************
// * JMR: For NINPC CHaracters
// **************************************
if
(strcmp(self->targetname,"blacksmith") == 0)
{
if
(++self->s.frame < 11)
self->nextthink
= level.time + FRAMETIME;
else
{
self->s.frame
= 1;
self->nextthink
= level.time + FRAMETIME;
}
}
else
{
// **************************************
if (++self->s.frame
< 247)
self->nextthink
= level.time + FRAMETIME;
else
{
self->s.frame
= 208;
self->nextthink
= level.time + FRAMETIME;
}
}
}
I’ll explain at the end of this tutorial.
Next locate SP_misc_easterchick (should be after misc_easterchick_think) and change this:
void SP_misc_easterchick (edict_t *ent)
{
ent->movetype
= MOVETYPE_NONE;
ent->solid
= SOLID_BBOX;
VectorSet
(ent->mins, -32, -32, 0);
VectorSet
(ent->maxs, 32, 32, 32);
ent->s.modelindex
= gi.modelindex ("models/monsters/bitch/tris.md2");
ent->s.frame
= 208;
ent->think
= misc_easterchick_think;
ent->nextthink
= level.time + 2 * FRAMETIME;
gi.linkentity
(ent);
}
To this:
void SP_misc_easterchick (edict_t *ent)
{
ent->movetype
= MOVETYPE_NONE;
ent->solid
= SOLID_BBOX;
// **************************************
// * JMR: For NINPC CHaracters
// **************************************
if
(strcmp(ent->targetname,"blacksmith") == 0)
{
VectorSet
(ent->mins, -16, -16, -24);
VectorSet
(ent->maxs, 16, 16, 32);
ent->s.modelindex
= gi.modelindex ("models/npc/blacksmith/tris.md2");
ent->s.frame
= 1;
}
else
{
// **************************************
VectorSet
(ent->mins, -32, -32, 0);
VectorSet
(ent->maxs, 32, 32, 32);
ent->s.modelindex
= gi.modelindex ("models/monsters/bitch/tris.md2");
ent->s.frame
= 208;
}
ent->think
= misc_easterchick_think;
ent->nextthink
= level.time + 2 * FRAMETIME;
gi.linkentity
(ent);
}
Explanations:
First, the procedure (misc_easterchick_think) only works with advancing the frames for a model. That way, the easterchick looked like she was alive and not some statue. All we did was, based on whatever was in the targetname, we would change the startframe [ self->s.frame = 1; ] and the end frame [ if (++self->s.frame < 11) ] of the corresponding model. So if targetname says “blacksmith”, it uses the blacksmiths frames to cycle through them.
The second procedure (SP_misc_easterchick) defines the model and its properties. As you can see, it doesn’t move and it’s a solid box so you can’t go through them. As before, we verify if targetname says “blacksmith” and if so, we change the models size (the VectorSet) or boundaries, we assign the model and we assign the start frame.
Ok, you say, everything looks all right but… WHAT THE HELL IS TARGETNAME? Well it’s a parameter that some entities use. It could be for a trigger or button, or a special event. In a level editor like QOOLE, you can point a button to a door to open it. Anyway, since targetname isn’t used for the easterchick, we’ll use it to specify what model to spawn. Of course, you have to have the model created in order to use it plus any frames or animation it might do ( like a blacksmith can hammer metal, a bartender can clean cups, a drunken guy can …. DRINK).
Well, on to the level. In QOOLE, on the menu, you select Object - Add Entity – Misc – Easterchick.

You then select Object – Entity Properties and in the field that says targetname, you write in the NINPC you want. This must be written in the same way you wrote it when you changed the code in g_misc.c [if (strcmp(self->targetname,"blacksmith") == 0) ].

Now, although you see the easterchick when editing in QOOLE, after you compile and generate the level, you will see the model that you wanted.
Final remarks:
You can use the same easterchick to show any number of different NINPC’s. Just add more “else if” statements with other NINPC names. You can also use the easterchick2 and eastertank for this. Since there are three of them, try categorizing them ( easterchick for female and eastertank for Male or easterchick for humans, easterchick2 for dwarfs and eastertank for elves).