|
Posted by metlslime on 2007/08/08 04:57:56 |
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. |
|
 |
 Maybe
#217 posted by Preach on 2009/02/05 20:00:32
I'd guess the whole onseam system was created because at the time it seemed like an unintuitive system to have vertices occupying the same position in the model, but connected to different triangles - when they are supposed to be part of the same surface in the model. The onseam method was a fix to the problem "how do I display the same vertex in two places on the skin?". It's just unfortunate that the solution pretty much ties you to the front/back skins that quake used.
Although I usually advocate the detached vertex solution, detaching things like that can cause problems. For example when calculating the vertex normals at that vertex, you probably want to average all the surfaces meeting at the split vertices, and give that same vector to all the vertices. This is a lot harder to do once you've split the vertices. In fact, if an unrelated vertex just happens to collide then you're scuppered...
Thankfully, .mdl uses precomputed vertex normals, so as long as you're converting from a format that supports merged vertices with split UVs then you can probably get sensible smoothing groups. Also, worrying about smoothing groups isn't the most pressing concern with quake models.
Interestingly enough, I don't know that onseam actually saves memory over all, when you consider how much wasted texture space there is as a result of using it. On models with lots of frames it's probably beneficial as the extra vertices would be recorded on all those frames. But for weapon models and other simple models, onseam probably doesn't make up for the waste.
#218 posted by gb on 2009/02/05 20:19:43
I think headgibs use their own models, which use their own skins.
 I'm Aware Of That
How difficult would it be to copypaste the faces from the head gib skins onto body skins? (I'm no modeller so I can't tell)
 Yeah
#220 posted by ijed on 2009/02/06 00:14:34
I want blinking lights for the enforcers, that was a good suggestion, whoever made it.
It looks from the models that the head gib was originally going to come from inside the main model, but it didn't work out.
Simple as export c+p import to put the pain head onto the normal guy for a dead skin.
#221 posted by gb on 2009/02/06 00:24:48
I was replying to Willem about the additional face parts etc. on id1 skins. Those are pretty weird.
 So Was I
#222 posted by ijed on 2009/02/06 02:03:42
It seems the extra faces are there because the head and model were originally going to be combined, until they realised that hiding the entire body inside a copied head would be more wasteful.
 Just Think....
#223 posted by metlslime on 2009/02/06 05:09:37
how awesome it would look if they did hide the body inside the head gib, now that we have engines that do model interpolation?
 Vampires!
#224 posted by Preach on 2009/02/06 10:07:26
Back in the day before I worked on mods that people would play, I made a quake mod where you fought vampires - aping Buffy and that kind of thing. One of the driving things behind it was to make the death sequences look cool (by quake standards), so when you staked a vampire through the heart they'd look agonised for a beat, then explode into a puff of dust.
Coming back towards relevance, when you killed them with fire the flames burnt upwards from their feet while their arms flailed. In order to make their legs disappear, the polygons were just folded up into the upper legs, then the torso, with the flame graphic concealing the interpolation which arose. I imagine the final effect is not too dissimilar to what metl's thinking of.
(ps: the head gibs are probably separate for the more mundane reason of giving them a blood trail, which is a per model effect...)
 Railgun In Quake
#225 posted by spy on 2009/02/06 10:43:02
is it possible?
i'd appreciate any help
#226 posted by Spirit on 2009/02/06 12:20:07
Sure, there were some mods with railguns I think.
 Ahem
#227 posted by Spirit on 2009/02/06 12:21:03
And I just remembered I once successfully completed this tutorial: http://www.inside3d.com/showtutorial.php?id=167
#228 posted by Trinca on 2009/02/06 12:28:32
Spy Parboil once change the qwprogs.dat to railmod i think... since u are russian is easy to ask in is forum :)
http://parboil.quakeworld.ru
#229 posted by Trinca on 2009/02/06 12:47:58
zomggg are you the spy from the old Parboil board?
hehe
 Quakec Question...
#230 posted by metlslime on 2009/02/06 12:57:59
what is the proper way to make an entity toggle between visible/solid and invisible/nonsolid?
So far, what i have tried is calling self.modelindex = 0, self.solid= SOLID_NOT to make it invisible, then doing SetModel(self, self.model), self.solid=SOLID_BBOX again to make it visible.
Visually, it works. But, once it's been invisible, it can never turn solid again.
So, is there a better way?
 Trinca
#231 posted by spy on 2009/02/06 13:18:01
what are you talking about?
psssst. trinca don't tell anybody that i'm russian it's a secret :))
p.s. thanks spirit for the link.......
 Zomggg
#232 posted by spy on 2009/02/06 13:19:18
i think i'm drukn again
 (in)Visible
#233 posted by Preach on 2009/02/06 15:30:46
To make it invisible and non solid, the following should suffice:
self.model = "";
self.solid = SOLID_NOT;
Not sure if adding self.modelindex = 0 adds anything to that, it might stop it being sent over the network.
To restore it again, use:
setmodel(self, *modelname*);
self.solid=SOLID_BBOX;
If you don't know *modelname* at compile time(eg a func_wall where the model is loaded from the map), then you need to stash the model info somewhere safe. Put a line like
self.mdl = self.model;
somewhere in the spawn function, and then use self.mdl in place of *modelname*.
If you're still having problems, try adding a call to setsize after setmodel
 Thanks For The Help...
#234 posted by metlslime on 2009/02/07 11:17:45
i finally got it to work, and here's how.
1) to enable being solid after turning inivisible and then visible again, i only ever set the model using setmodel once, and from then on alternate between setting modelindex to 0 or the actual index.
Since setmodel is never called, the entity stays linked into the world with the original physics bounds. self.solid can be changed without issue.
2) for entities that are set to START_OFF, there was still a problem where they'd never appear at all, and never become visible. My hack solution is to wait 1 second, then make them invisible/nonsolid in a special think function, rather than in the spawn function.
 Good
#235 posted by madfox on 2009/02/07 17:52:32
explanation to make a monster invisible.
I'm still trying to find the right colours to improve Spectre in its translude way.
And as it is a sprite it has a funny way of walking. I think more darker colours on the outside and transparant inside.
http://members.home.nl/gimli/spectr.jpg
 Can Be Shot But Doesn't Collide With Walking?
#236 posted by JneeraZ on 2009/02/13 21:52:05
I'm probably going to think of the solution 5 seconds after asking this but ... let's say I want a monsters corpse to be shootable but I don't want it to collide with other corpses or the player. I just want it to react to gunfire (both instant hit and missiles).
Doable?
 Look At The Corpse, It's Voodoo QC Dancing...
#237 posted by Preach on 2009/02/14 01:59:02
It can't be done easily. I say that because darkplaces has an extension for just this purpose, where you can make an entity SOLID_CORPSE, which behaves like you say. The following is ugly, not only in itself, but also in the dark secrets about standard ID1 code it exposes. Read on if you dare...
The key thing is that you can't change the .solid status of things during touch functions, it can cause engine crashes. So, the vast majority of the time, you want your corpse to be the same .solid type as a trigger_multiple entity, which is SOLID_TRIGGER.
We're going to use the grunt as our test dummy here. This is the kind of thing you need to do in your death sequences, during the frame that usually makes the monster SOLID_NOT:
void() army_die3 =[ $death3, army_die4 ]
{
self.solid = SOLID_TRIGGER;
setmodel(self, self.model);
self.touch = corpse_touch;
self.health = 20;
self.takedamage = DAMAGE_AIM;
self.th_die = GibPlayer;
self.th_pain = SUB_Null;
self.ammo_shells = 5;
DropBackpack();
};
We make it SOLID_TRIGGER, then call setmodel in order to link it, which prevents a "trigger in clipping list" crash. We make it's touch function corpse_touch, see below. We also make it damageable again, give it 20 hp, and define both th_die AND th_pain, the latter being important if you don't want to reanimate your corpse.
So here's the deal. In this state(SOLID_TRIGGER), when a missile collides with one, you get a touch event where the trigger is self and the missile is other. You do not get one where the missile is self and the trigger is other! I'm not sure if this is an optimisation just for missiles, or that any entity touching a trigger doesn't set off its own touch function. In any case, we're about to cheat:
void() corpse_touch =
{
local entity oself;
if(other.movetype != MOVETYPE_FLYMISSILE && other.movetype != MOVETYPE_BOUNCE)
return;
oself = self;
self = other;
other = oself;
self.touch();
};
See what we're doing? The first bit of code is just so that we don't bother doing anything if we aren't hit by a missile. You might want to use a different criteria for what is a missile, I went for something that required no changes elsewhere. Then we create a touch event on the missile by the trigger, but by hand instead of from the engine.
Once you've done that, you might think we're done for missiles now, and you can give it a try by lobbing a grenade into a corpse. It'll explode on contact as desired (you can of course change the corpse's .takedamage to DAMAGE_YES if you want to prevent grenades from detonating on contact, I set it like this for illustrative purposes). However, if you fire some nails into your corpse, you might be surprised to find nothing happens.
The reason for this is due to some entirely redundant code in the original QC, which must have been moved engine-side for performance, but then remained in the QC source by mistake. Look at the start of spike_touch in weapons.qc:
void() spike_touch =
{
if (other == self.owner)
return;
if (other.solid == SOLID_TRIGGER)
return; // trigger field, do nothing
...
You'll actually notice the first line in the code for almost all quake missiles. It's totally pointless, as the engine never makes collisions between entities and their owners. Just think how many times that code has been called in a million deathmatches across the world, and not once has it been true...
As we discovered near the top of this section(and to be honest I never knew about this before I tried today), SOLID_TRIGGER entities don't generate touches on missiles either, so the next line is similarly pointless. To get things working, comment both statements out, and do the same in superspike_touch. If you're bored, get rid of the self.owner lines in the grenade and the rocket.
If all has gone to plan, at this point all the missiles will damage the corpse.
Join us after the break when we investigate the shotgun and other tracelines...
 You Can't Talk To A Man With A Shotgun In His Hand...
#238 posted by Preach on 2009/02/14 02:59:57
Before we start the business proper, I should alter you to two bugs with the code which only became apparent once the grunts started hitting corpses with their shotguns. The first is that when monsters begin infighting, they don't realise that their target monster has died when they become a corpse. This is because they consider their enemy dead if their health is below 0, but the corpse has positive health. The fix for this is left as an exercise.
Also, if the corpse gets damaged by another monster, it will get resurrected. To prevent this, add the line
self.flags = self.flags - (self.flags & FL_MONSTER);
when creating the corpse.
~~~~~~~~~#~~~~~~~~~
Ok, so the question is, how do we deal with weapons that use a traceline. And the solution is we make the corpse solid only for long enough to perform the tracelines. We in fact toggle the solid state of all the corpses in the map. Although in theory we might end up changing the solid status of something during a touch function(if a touch caused a shotgun to fire, for example) we hopefully* put everything back before the engine can notice.
So the simplest way I could think of to change all of the corpses to solid and back was: give all of your corpses the classname "corpse", then use the following functions to toggle the solid status:
void() corpse_solid_on =
{
local entity corpse;
corpse = find(world, classname, "corpse");
while(corpse)
{
corpse.solid = SOLID_BBOX;
setmodel(corpse, corpse.model);
corpse = find(corpse, classname, "corpse");
}
}
void() corpse_solid_off =
{
local entity corpse;
corpse = find(world, classname, "corpse");
while(corpse)
{
corpse.solid = SOLID_TRIGGER;
setmodel(corpse, corpse.model);
corpse = find(corpse, classname, "corpse");
}
}
The trick is then to surround calls to traceline with these functions. The axe is very simple, just put corpse_solid_on(); on the line above the traceline and corpse_solid_off(); on the next line after it.
For the shotgun, it's worth remembering that there are lots of calls to traceline in a single blast, and since toggling the solid status is fairly expensive in terms of performance, we should do it once per blast. So sandwich the functions around the
while (shotcount > 0)
{...}
block.
The lightning gun is left as a small exercise, but it's only really worth wrapping the first traceline in the function, the other two are basically enormous bugs which speedrunners exploit to kill things through walls.
That's almost it, but there's one finishing touch. If you go up point blank to shoot a corpse, you'll find that your shot disappears, or attack does nothing. This is because the traceline starts inside an entity, and so the returns from the traceline are a bit weird. The telltale signs of this happening are:
trace_fraction == 1 (not 0 as you'd expect)
AND
trace_ent != world (if it is world, then the trace really did hit nothing)
So what we do is add a bit of extra code which can cope with this case to the various weapon attacks. As an example, add the following code just below
if (trace_fraction != 1.0 )
TraceAttack (4, direction);
in the shotgun firing code:
else if (trace_ent != world) //if so, we are stuck inside what we have hit
{
trace_endpos = src + direction*16; //set some reasonable values
trace_fraction = 16/2048;
trace_plane_normal = -1 * direction;
TraceAttack (4, direction);
}
The code for the axe/lightning gun is similar, but if people get stuck on that exercise I can supply good fixes.
Well, that wraps things up for today. I would say that this latter part is quite an ugly hack, but the code in the first post is actually fairly clean. In all cases you should ask yourself "Would I show my mother this code" before you do something you might regret.
As a final parting thought, you might want to adjust the height of the bounding box of the corpse from the default, so that shots at head height don't blow up the corpse. If you do, remember that you need to do this in both of the corpse_solid toggling functions.
*I say hopeful, but I'm pretty sure it should work. I'm just not sure how careful the engine is at checking, and it's such an awkward thing to create a test case for. So I'm gonna be cautious in my endorsement.
#239 posted by JneeraZ on 2009/02/14 11:14:18
Preach, you are fucking awesome. :) Thanks man, I'm off to digest all of that.
#240 posted by JneeraZ on 2009/02/14 12:59:11
Absolutely beautiful, that all worked. Thanks again!
 Yeah
#241 posted by ijed on 2009/02/18 14:05:06
That's very nice, thanks for the explanations.
|
 |
You must be logged in to post in this thread.
|
Website copyright © 2002-2025 John Fitzgibbons. All posts are copyright their respective authors.
|
|