News | Forum | People | FAQ | Links | Search | Register | Log in
Coding Help
This is a counterpart to the "Mapping Help" thread. If you need help with QuakeC coding, or questions about how to do some engine modification, this is the place for you! We've got a few coders here on the forum and hopefully someone knows the answer.
First | Previous | Next | Last
Hierarchy 
Expanding the available functions is exactly the sort of thing that was motivating me. The feeling I have is that there's a tension between adding all the fields a monster could ever need and not burdening all the other entities in the game with stuff they don't use. This leads us to the current compromise where the most vital events get handlers and the rest get hacks.

Adding new fields is possible, but if you wanted to support 50 or 60 events it would get pretty crazy. In a world where lots of monsters shared th_melee or th_stand functions, or even where such things might change dynamically for a given entity (like an injured monster switching to a limping run) the current architecture would have more weight. But as it is, you're born with the think functions of one class, and you die by it, so why not bundle the whole package into one function for the monster to carry about? 
 
i know what you mean about the th functions...
i run into it when designing a boss monster that doesn't fit into the standard mold of 1 melee, 1 ranged.

i usually end up overriding the checkattack function for those monsters with a function that directly calls whatever attacks are needed.

still, a function field is stored as, what, an integer? or float? 32 bits is not really a big deal, even with thousands of entities.

seems like it would be more hard to deal with code where there is a single entry point for all monsters and hundreds of checks for each one.
that would be very annoying, i'd think. 
Sketching 
You could have a list of the events starting with the mandatory ones

//====MANDATORY====
float EVENT_STAND = 1;
float EVENT_RUN = 2;
float EVENT_MELEE = 3;
...
float EVENT_WAKE
float EVENT_DIE = 8;

//=====OPTIONAL====
float EVENT_OPTIONAL_START = EVENT_DIE + 1;
float EVENT_STRUCK_BY_LIGHTNING = EVENT_OPTIONAL_START;
float EVENT_SHOT_MIDAIR = EVENT_STRUCK_BY_LIGHTNING +1;
...

Then the pattern for event handling goes:

void monster_shamber_handler(float eventnum)
{
��if(eventnum < EVENT_OPTIONAL_START)
��{

��//code to handle events all monsters are expected to deal with
��//even if grunt response to EVENT_MELEE is no-op etc.
��return;
��}
��else
��{

��//handle any other selection of events with set of if..else lines
��}
}

In theory you could do some sort of jump table with the mandatory events using the event number as an index. Of course, since qc doesn't really handle integer calculations all that well you'd probably find the most efficient solution was to redefine all the event numbers to already be the desired offset into the table stored as an integer bytewise. Assuming you need 4 qc instructions per handler to call a function and return you'd be looking at

float EVENT_STAND = 0.00000000000000000000000000000000000000000000056051938;

And so on...wasn't there a compiler that let you define integer constants like %4
HUD Text Shizzles 
I've never ever looked into mucking around with the HUD before - but would like to do one thing if possible...

You know when you press tab to see your monster and secret counts? Is it possible with QC to change the text "secrets" to say something else? As well as on the end level tally screen? 
Kinn: 
the score bar (when you press "tab") is hard-coded in the engine.

The intermission screen is an image, so you could edit that image to say anything. 
Ah Ok 
hmmm, so i can change one but not the other :/ 
 
you could always make your own menu/screen.

even with stock quake exe you can make a functional menu that pauses the game. 
 
you could always make your own menu/screen.

Nah that would be huge overkill for what I'd be doing. Besides, I realised what I originally had in mind is probably just a silly gimmick anyway, I'm gonna shove it to one side for now. 
Brushmodel Texture Swapping 
So let's say I have a brushmodel and i want the texture it wears to change according to events. From what I understand, all I can do is this:

- have an (optionally) animated looping texture with frames following the +0blah, +1blah etc. convention, then change to a non-animated image with the +ablah naming convention, by setting frame = 1 on the bmodel.

What I'd like to do is have 4 different non-animated textures, and i can just swap between any one of these images.

I assume it's not possible without doing crap like having 4 seperate bmodels and hiding 3 of them (or I guess just using 2 if i abuse +0blah and +ablah).

Or is it?

Also I don't wanna use a .mdl 
 
yeah, you'd need multiple bmodels.
the frame stuff is hard coded, unfortunately and treats +0 ... +9 as a frame group, hence frame = 0 and 1 only. 
Ok Cheers 
I'll move to plan B which is to do the effect with sprites. Lighting won't be ideal, but i think i can get away with it. 
Lightning Bolts 
so, spawning a lightning bolt:

WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteCoord (MSG_BROADCAST, self.enemy_pos_x);
WriteCoord (MSG_BROADCAST, self.enemy_pos_y);
WriteCoord (MSG_BROADCAST, self.enemy_pos_z);

no matter what i set the vector org to, it only spawns the bolt starting from the entity origin - basically the calls for setting the starting point are ignored - is that how quake works? 
Only If The Given Entity Is A Player, Otherwise It Works As Expected 
 
Ah I See 
sneaky, sneeaky quake :} 
 
note also that you can only have one lightning bolt per entity.

these days i build my lightning bolts manually out of edicts because every engine besides fq/qs tries to be cute and put in effects. :( 
Stealing Weapons 
What do I need to consider when trying to implement something like this:-

void() steal_weapons_use
{
other = activator;
if (self.spawnflags & SPAWNFLAG_SHOTGUN)
{
other.items = self.items - (self.items & IT_SHOTGUN);
other.ammo_shells = 0;
other.weapon = IT_AXE;
}
};

Or am I running in treacle here?

I can see it taking the weapon and the shells, but it breaks with an error in the weapon_cycle command. 
Activator's Other Self 
There seem to be three entities in this story, and I'm having to guess who is who:

self: presumed to be an entity added to the map as a trigger perhaps?
activator: if the above is correct then activator is whoever set off the trigger called self
other: known to be the same entity as activator

The first thing seems to be that other is unnecessary, which makes the function confusing. If we replace other with activator we get:

void() steal_weapons_use
{
�if (self.spawnflags & SPAWNFLAG_SHOTGUN)
�{
��activator.items = self.items - (self.items & IT_SHOTGUN);
��activator.ammo_shells = 0;
��activator.weapon = IT_AXE;
�}
};

We can then see more easily what might be dangerous. We only act if self has the spawnflag for removing shotguns. On that condition, we then set the activator's items to be equal to self's items with item shotgun removed. I'm pretty sure that this line should be referring to activator all the way through. 
Thanks Preach 
I didn't see the wood for the trees. 
 
don't know if you trimmed things out for clarity, but you should probably add a quick check:
if (!activator.flags & FL_CLIENT)
return;

just to avoid any possible problems in the case of monsters some how activating it. 
Spawn() 
is spawn() completely reliable? is there any time where it can fail and not create anything? or it creates an entity but the entity somehow gets lost? maybe if you're spawning many entities in the same think? 
Invalidation 
In the standard implementation spawn only fails if there are no free edicts, which produces a game-ending error. As long as it doesn't error out, it returns some entity and as far as I can see there's no way this entity could fail to be a clean slot. But that entity might be more familiar than it seems.

Edict slots aren't allowed to be reused with 0.5 seconds of an entity being removed from a slot*. However, if a reference to an removed entity persisted longer than that it could end up creating a reference invalidly relating to a newly spawned entity. Could a stale reference be somehow responsible for your issue?

*This is not true for the first two seconds of the map, in order to not waste lots of slots if entities are loaded from the map but removed by the qc straight away. 
 
right, i totally forgot about that! i still had that .doNotRemove trick from before and i found that the entity is indeed being removed by something else. thanks, i'm off to track that down. :P 
And 
it's done. thanks! turns out i had some sloppy linked list clean up. i was clearing out the list but forgot to clean up the head link. :P 
Not Qc... 
this is java, but it's more of a conceptual thing...

finally started working on the inheritance aspect of fgd files for my fgd<>def converter thingy...

essentially, i have multiple lists of objects which represent key/val pairs. these lists can have duplicate entries from base classes that an entity inherits from.

eg: you have 'monster_army' which inherits target/targetname fields from the base 'monster' class.

what i'd need to do is, on demand, collapse the multiple lists into a single one.
ie: when i 'get' a list element, i should iterate through a single apparent list:

monster_army has the fields: (inherits from 'monster')
0: B
1: C
2: D

monster has the fields:
0: E
1: C
2: A

should look like:
0: B
1: C
2: D
3: E
4: A

(duplicate C in 'monster' is ignored because 'monster_army' already had that field)

i can work through the logic of building a new list myself, but the problem is that there are many times where i need to iterate through the (final) list, so every time i .get(i), i'll have to rebuild this list which feels wrong.

is there maybe some more complex data structure that would work better for this? i'm thinking maybe trees due to their non-linear nature?
unfortunately, i've never really learnt data structures more complex than a simple linked list. :S

or maybe there's some absurdly easy solution and i'm just not seeing it. 
 
you should be able to get away without building the final list. I'd store the key/value pairs in a hash table instead of a list of key/value pair objects, and have an object for each "quakec class". then set up a recursive get() function which first checks the object-being-called's key/value pair mapping (e.g. Grunt), and if the requested key wasn't found, call the get() method on the superclass (e.g. Monster) (or return null if there is no superclass - so for a key requested that isn't in either Grunt or Monster).

something like this:

class EntityClass {
EntityClass superclass;
HashMap<String, Object> fields;

Object get(String key){
if (fields.containsKey(key)) {
// the requested key is stored directly in our class
return fields.get(key);
} else {
// the requested key is not in our class, try searching
// our superclass.
if (superclass != null) {
return superclass.get(key);
} else {
return null;
}
}
}

}

hope that helps..

btw here's the javadoc for HashMap.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/HashMap.html 
First | Previous | Next | Last
You must be logged in to post in this thread.
Website copyright © 2002-2025 John Fitzgibbons. All posts are copyright their respective authors.