|
Posted by ijed on 2008/08/24 20:31:46 |
Thought I'd start a thread on this, it could have gone in Gameplay Potential, but this is more specific.
What are the favoured special abilities for monsters to have?
Shield
Homing shots
poison
wall / ceiling climbing
leaping
explosive death
ressurection
cannabalism
spawning / cloning
Teleportation
Dodging
That's off the top of my head, anyone have any other cool ideas or concepts?
And what new abilties could the old monsters have - like Scrags that change to swimming if they enter water (thanks text_fish) or an Ogre that pisses on the player after killing them (thanks Romero). |
|
|
Better Yet
#196 posted by Lardarse on 2008/09/16 01:35:20
Just make them hull1. Doesn't sort out the stairs thing, but it solves nearly everything else...
Fiend Jumping Trick
#197 posted by Preach on 2008/09/16 01:43:21
I'd be wary of doing something like bumping them up 16 units, in places with low ceilings you'd run the risk of them getting stuck in the ceiling, and then they're a worse sitting duck.
What might work better is giving a little extra horizontal velocity to the fiend at the apex of its jump. This would be a bit like the air control the player has, just nudge them forwards by 10-20 units/second. That should be low enough that you wouldn't notice the extra speed if they're making a full leap. Ordinarily the fiend gets stuck because all the horizontal velocity is zeroed when he hits the step at the start of the jump. If you give it him when he's already high enough to clear the step, then it should work.
Of course, that little velocity won't get him up more than one step per jump. Perhaps if you started him off a little slower in the horizontal direction and gave him multiple small boosts during the jump you'd get better results. I'd recommend storing the initial jump direction for all of these calculations, you shouldn't be letting the fiend correct its course mid-flight.
Also Fiend Bug
#198 posted by Preach on 2008/09/16 01:47:34
To get rid of the fiend instakill leap bug, add some code just after the damage code in the touch function. Check to see if the "other" entity is still alive after the touch. If so, then prevent the fiend from doing any more damage in this leap by setting a flag, for example setting self.worldtype to 1. Then you need to check for this flag before the damage is inflicted. Also be sure to reset this flag each time the fiend launches a new jump.
Wouldn't That Save Me From Multiple Fiend Impacts At Once?
#199 posted by Lunaran on 2008/09/16 07:19:10
The demon_jumptouch function is supposed to reset its self's touch func when it's called so it only does damage once, and that doesn't seem to happen (so if you're running at a fiend as it's leaping it's like being under a crush door). why is that?
Jonesing For A Fix
#200 posted by Preach on 2008/09/16 10:12:36
Because the flag would be recorded per fiend, you'd still take damage from multiple fiends hitting you. The reason it doesn't cancel after one hit can be found in the if(!checkbottom(self) block. This checks if the fiend is properly onground, basically if it's on flat navigable ground. If this is not the case then it's still in the air, or stuck on a steep slope. The inner if statement checks for FL_ONGROUND, which would mean it's on a steep slope. In that case it resets the touch function and goes for another jump.
However, most commonly if checkbottom is false, the fiend is off the ground with no FL_ONGROUND, so it just goes to the return at the bottom of the block without changing the touch function.
Normally when two entities collide side to side and stay in contact they don't get repeat touches called, so even if you run at the fiend which is leaping, you only take one ping of damage. In theory if you could hit it, back off and hit it again you could take damage twice but it's not easy to do that.
When a fiend lands on your head it's a bit different. For some reason quake registers a touch every frame for vertical collisions like this, possibly the gravity code, I couldn't say. But isn't the fiend at rest as soon as it comes to rest on your head? Sadly, standing on an entity doesn't count for checkbottom, and even worse, the sliding bbox effect is caused because you don't get FL_ONGROUND on top of such an entity. So the fiend decides it's in the air the whole time, and you keep getting hit.
Now That Bug...
#201 posted by Shambler on 2008/09/16 11:24:43
...I would totally agree with fixing. Because it's a game-breaking insta-death bug. Unlike, say, Ogres who can't aim right, the Fiend bug really fucks your gameplay experience up on the occasions when it happens. That is probably the best reason for fixing anything...
Couldn't You
#202 posted by megaman on 2008/09/16 12:45:12
just let the finds run a bit more than they do now and make them climb up stairs while running?
P.S.
#203 posted by Shambler on 2008/09/16 13:05:10
Fiends:
1. Don't have eyes.
2. Are an awesomely cool monster.
More Running, Less Jumping
#204 posted by Preach on 2008/09/16 13:32:51
Yeah megaman, this would be another good way to prevent stairs from blocking fiends. You could add an self.attack_finished time to the jump which is a bit longer than the length of a full jump, all frames included. Then make sure that DemonCheckAttack checks for it before making a jump(although it should be ignored for melee attacks as usual).
Alternatively you could just extend the jump sequence by adding
void() demon1_jump12 =[ $leap12, demon1_jump13 ] {};
void() demon1_jump13 =[ $run1, demon1_jump14 ] {};
void() demon1_jump14 =[ $run2, demon1_run3 ] {};
You'd also want to actual put some ai_face(); movetogoal(n) stuff to make it move during those last two frames without calling ai_run. I don't think this would be the best way to do it though.
This would make the fiend slightly slower to rejump in all situations though. You could make it a bit smarter about this by calculating at the start of the jump the rough endpoint of the jump under the assumption the fiend isn't obstructed, and store that in self.pos1. Also store the current position, or somewhere a little behind the fiend in self.pos2.
Then in demom1_jump11 (the first landing frame) decide if the fiend's origin is nearer pos1 or pos2. If the former, then the jump went well and continue as normal. If you're still nearer pos2 then put an attack_finished time on of half a second or so, making sure you won't jump for a while. The reason you might want to put pos2 some way behind the fiend is so that the jump doesn't have to get more than half way to count as a "good jump". Just make sure that if the fiend goes nowhere/essentially nowhere, pos2 is going to be nearer.
The attack_finished trick is already used for the pyro in quoth, to make sure that after each shot he tries to close the distance with you. It's pretty neat, but you do have to be careful when thinking about nightmare skill. If you use SUB_AttackFinished to set your attack_finished value then you won't get the behaviour in nightmare mode. So you should only use that subroutine if the attack_finished time is intended to make the monster less dangerous.
That Won't Work
#205 posted by Sielwolf on 2008/09/16 16:11:19
unless luns_mom_jumptouch is triggered previously and in sequence.
sorry dunno what's got into me :E
Advanced Lessons In Fiend Tweaking
#206 posted by Preach on 2008/09/17 23:44:07
So I had a go at implementing the first fiend stair fix, and ran into a snag pretty quick. Almost instantly after the fiend jumps into a set of stairs the touch function decides the fiend is on ground and jumps to demon1_jump11, thereby bypassing the velocity boost added to demon1_jump5.
(to avoid confusion, in the rest of the post "frame" means a server frame, animation frame functions should just be called by name)
As far as I can tell, in the first frame after the jump starts, the function checkbottom returns true even though the fiend is off the ground, and has just banged into a wall. I suppose that this might be a consequence of the order things run in the physics engine, that touch functions occur before the information that checkbottom relies on is updated.
In any case, if you set
self.t_length = framecount;
in demon1_jump4, and then add
if(framecount == self.t_length + 1)
return;
in DemonJumpTouch just before
self.touch = SUB_Null;
self.think = demon1_jump11;
self.nextthink = time + 0.1;
Then the jump actually reaches demon1_jump5 so the physics trick can go ahead. And then it does in fact work. It's good enough that the fiends in e1m3 only get stuck once or twice before leaping up to you, even if you try and glitch them in place.
Stay tuned for part II where I see what the other fix does for the fiend.
Advanceder Lessons In Fiend Tweaking
#207 posted by Preach on 2008/09/18 00:28:34
So, armed with this knowledge, I decided to try the other way. The basic method is to add
if (self.attack_finished > time)
return FALSE;
to CheckDemonJump.
The trick is knowing when to apply the waiting time. In the last post we had to work around the problem of the jump cancelling at the first available opportunity, but here we can use this to our advantage. It turns out that if that happens, it's very likely that the fiend is stuck on some stairs. So we put the same line into demon1_jump4:
self.t_length = framecount;
Then in the same place in DemonJumpTouch we add
if(framecount == self.t_length + 1)
self.attack_finished = time + 1;
And just like that fiends will walk a way up stairs if they jump into them, it actually looks quite natural. I went for a 1 second gap, because it takes about half a second for the fiend to actually land again and begin to run. If you wanted to get more sophisticated you might vary the time based on how much higher the player way, but you would have to ask if the sophisticated way would actually perform better.
The source I came up for each of these methods can be found at
http://www.btinternet.com/~chapterhonour/demon_variantsl.zip
[warning: the insta-kill fix has not been applied to these files, and in the case of the first one it's really worth doing, as the extra velocity boosts could make it inflict multiple hits]
If you notice a strange alteration to one of the jump functions, you may want to read the next post, which gets really nitpicky about it.
Some food for thought to finish with. The second method only alters the way in which a fiend chooses to use it's abilities, rather than adding a new dimension to it. So it might sound like a fairly faithful and "safe" alteration. However, remember that all that differentiates the majority of nightmare monsters from their regular skill counterparts is when they decide to use their attack and pain sequences...so the decision process matters too.
Another Fiend Bug Caught
#208 posted by Preach on 2008/09/18 01:08:27
Take a look at this shot:
http://www.btinternet.com/~chapterhonour/fiendbug.jpg
How did the fiend end up through the wall, so high up in Gloom Keep?
The eagle-eyed might have spotted the alteration I alluded to above, it was a setorigin call in demon1_jump4. Nobody saw that? Fair enough...
You might be thinking that I was trying to sneak Lunaran's 16 unit lifting fix into the mix as well. Actually, the code that lifts the fiend 1 unit off the ground is in the original ID source, but they do it as:
self.origin_z = self.origin_z + 1;
This is bad practice, as you aren't meant to set the origin of an object without calling setorigin(but you can get away with it if the object isn't solid yet). So I thought I was fixing a bug.
It turns out I was fixing a bug after a fashion, but only in the sense that the original line is a bug, and the fixed line is a bug with the proper function call. Because there's no checking for low ceilings when the line is called, the fiend can be bumped up into a stuck position.
It's not easy to do this, as quake monsters won't walk into a place where there's no clearance between the top of their bbox and the ceiling above them. Due to grid snapping, you need to use sloping surfaces to make the gap smaller than 1 unit. The small doorway below the fiend in the screenshot offers one such place, as the doorway has 45 degree bevels at the top. If you jam the fiend into the doorway and make it leap into the door frame enough times, eventually it'll do it close enough to get stuck. The 1 unit bump just moves its bounding box into the sloped roof of the doorway.
Then once the fiend is stuck, it tries to jump its way free. Each jump it tries to make begins with the 1 unit bump, so it gets stuck further. If you go away and do the crossword for a bit, the end result is what you see in the screenshot.
Now, I believe I'm right in saying that the line should just be commented out, because lifting the fiend off the ground like that is unnecessary. From trial runs, the fiend certainly jumps just like before. Unless someone can suggest a more unusual case when the height bump is needed, I think the line only causes the occasional bug.
Jump!
#209 posted by Lardarse on 2008/09/18 01:43:34
Do the other monsters that use leaping attacks (dog, spawn, that's it, isn't it?) have these issues as well?
Bump!
#210 posted by Preach on 2008/09/18 01:51:08
Both of them have the same line that increases their height by 1 unit each time they jump, so if you're fixing that for one, fix it for all of them. I've not checked if they have the same problem jumping into stairs, so it could go either way. The best way to verify that would be experimentally. The same kind of approaches to fixing them should work, if they are problems.
Dogs And Spawn
#211 posted by Preach on 2008/09/18 14:18:55
(gee, I just love this thread)
Spawn don't have the same problem with stairs because they become MOVETYPE_BOUNCE when they start jumping. This means when they collide with a stair, they bounce back off it, and so they launch their next jump with enough of a run up to clear the obstacle.
If you look in the dog.qc file, there's a comment
// if close enough for slashing, go for it
which suggests the whole thing is a big copy-paste from the fiend file. Technically you can get dogs stuck jumping in the same way, but it's harder to do, as dogs will only leap at you under very specific circumstances. You have to be between 80 and 150 units away, which isn't easy to judge.
Still, if it bothers you enough you can fix it by copy-pasting the lines of code from demon.qc. Hell, it's what iD did...
Heheh
#212 posted by meTch on 2008/09/18 18:47:01
can make them jump too you if u r using some cranked stuff
Hey Preach
#213 posted by necros on 2008/09/19 02:33:24
why is:
self.origin_z = self.origin_z + 1; // raise off floor a bit
in walkmonster_start_go?
i'm guessing it has to do with either droptofloor or the somewhat hacky use of walkmove to print out the debug message?
and what exactly is the difference between setting origin directly anyway? what does that mean 'messes up entity links' or whatever. i've always used setorigin but never really understood why.
Necros
#214 posted by Lardarse on 2008/09/19 10:11:50
I think droptofloor requires it. Similarly, the items need it as well.
Also
#215 posted by necros on 2008/09/19 10:44:05
why is FL_FLY broken?
a walking monster without FL_FLY will fail on a walkmove(0,0), but a flying monster (with FL_FLY) will pass, even if it is inside a wall. this is probably why scrags can sometimes 'noclip' through walls.
some cool shit could be done if the walkmove check functioned properly with FL_FLY. :(
Questions
#216 posted by Preach on 2008/09/19 12:14:18
Yeah, I agree with Lardarse, it's so that the monsters actually have a distance to fall with droptofloor, even if the mapper placed them flat on the ground. I've never checked what happens if you omit it, it might be that the monster gives off the warning message for being stuck. I don't think it's such a bug risk though, because mappers have to account for it in monster placement.
setorigin does a lot of behind the scenes work which is hard to understand. One of the most transparent things you can see it do is update the absmin and absmax of the entity(including the extra size for FL_ITEM entities). The next step is to link to the PVS leafs, which I think determines where the entity is visible from(but I don't know the engine source well).
The next thing the function does is recurse down the tree of areanodes to find the first node which crosses the bounding box of the entity. It then adds the entity to the linked list of all other entities which cross that areanode. This is the important physics thing which you break if you don't use this function. When you change the origin directly, your entity will be in the wrong list of areanodes, which may mean it misses collisions.
The idea behind the walkmove(0,0) is that it returns FALSE if the monster couldn't move the entire distance in the desired direction, and TRUE if it did, which is meant to be used for detecting when a monster has just walked into a wall. If you look at the engine code which governs it, you see that actually flying and swimming monsters have almost no walkmove code in common with walking monsters. By contrast, the only difference between FL_FLY and FL_SWIM is that if the endpoint for a FL_SWIM monster would leave the water, then the fish doesn't move and FALSE is returned.
The other thing that's important to note is that other than that for FL_SWIM, the only reason the move can fail for a flyer/swimmer is if the trace_fraction from the attempted move is not equal to 1. If you're moving 0 distance, then this cannot fail. In the walking case, there's a lot more going on to check for stairs, including checking whether the trace is allsolid. The check ties into deciding whether the monster needs to step up/down, specifically whether the trace is "startsolid". Because some degree of solid tracing can occur even in a sucessful move, it's important that the case of the whole trace being solid is dealt with by returning FALSE straight off. As a side effect it spots when the monster is stuck.
Preach
#217 posted by gb on 2008/09/20 18:52:05
Those links don't work for me :/ Can you put the fix on shub-hub or something?
Quick Question
#218 posted by Zwiffle on 2009/06/10 23:00:34
Any love for a small Quake monster art event? Something just as simple as "Draw/sketch an original quake-themed monster" or something?
Yes
#219 posted by ijed on 2009/06/11 00:36:36
Yeah
#220 posted by Tronyn on 2009/06/11 00:46:19
if it's in the next couple weeks, or in august
|
|
You must be logged in to post in this thread.
|
Website copyright © 2002-2024 John Fitzgibbons. All posts are copyright their respective authors.
|
|