 Hierarchy
#672 posted by Preach on 2012/02/18 23:01:31
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?
#673 posted by necros on 2012/02/18 23:27:32
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
#674 posted by Preach on 2012/02/18 23:33:18
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
#675 posted by Kinn on 2012/02/21 19:35:29
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:
#676 posted by metlslime on 2012/02/21 19:44:34
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
#677 posted by Kinn on 2012/02/22 00:30:35
hmmm, so i can change one but not the other :/
#678 posted by necros on 2012/02/22 00:40:13
you could always make your own menu/screen.
even with stock quake exe you can make a functional menu that pauses the game.
#679 posted by Kinn on 2012/03/04 00:26:36
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
#680 posted by Kinn on 2012/03/06 16:36:20
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
#681 posted by necros on 2012/03/06 19:40:49
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
#682 posted by Kinn on 2012/03/06 20:06:44
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
#683 posted by Kinn on 2012/03/07 17:52:54
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
#684 posted by czg on 2012/03/07 18:40:50
 Ah I See
#685 posted by Kinn on 2012/03/07 18:44:17
sneaky, sneeaky quake :}
#686 posted by necros on 2012/03/07 21:10:16
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
#687 posted by Mike Woodham on 2012/03/10 15:29:42
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
#688 posted by Preach on 2012/03/10 16:03:07
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
#689 posted by Mike Woodham on 2012/03/10 16:20:21
I didn't see the wood for the trees.
#690 posted by necros on 2012/03/10 18:36:38
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()
#691 posted by necros on 2012/03/10 19:10:01
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
#692 posted by Preach on 2012/03/10 19:24:36
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.
#693 posted by necros on 2012/03/10 19:39:50
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
#694 posted by necros on 2012/03/10 19:55:18
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...
#695 posted by necros on 2012/03/17 06:23:27
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.
#696 posted by ericw on 2012/03/17 07:13:59
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
|