|
Ideas
#8216 posted by than on 2009/01/13 08:36:50
You could always use a clip wall with small regular brushes textured with skip at the extremes to stop it being glitchy and then kill it when the player gets close. That should work ok whilst allowing line of sight checks to work and projectiles to pass through.
Personally though, I prefer the tip posted by Metl, which I used in a couple of maps in the past - maybe even as far back as apsp1. I like that it doesn't block them movement of jumping or flying monsters, since I will typically want to use it to hold a sniper in place somehow. I may have actually made a small demo map to demonstrate this quirk of clipped brushmodels some time ago, so I will see if I can find it tonight.
Another way that requires no entities and will stop strict walking (no jump attack) monsters is to create a small break in the floor where you want them to stop. Monsters often have problems with floors that have a lot of holes in such as gratings because they do some kind of line of sight check to make sure there is ground below them. When there isn't, they won't keep moving forward. I think the crack only needs to be 16 units wide for it to work, though it needs to be a bit deeper than that. You could then cover the crack up with a func_illusionary if you wanted, though that is not neccessary, and would obviously look shit if a grenade fell in the crack.
Other suggestions include using a trigger monsterjump to fire the monster back very slightly (it may be worth experimenting with speed and angles here) or just embedding it slightly in the wall, which requires no extra entities but is a bit hacky and might not work in all engines.
All of these tips should work in vanilla quake.
Sorry
#8217 posted by than on 2009/01/13 08:38:16
didn't notice metl had already posted the tip about using a gap in the floor.
Sorry
#8218 posted by than on 2009/01/13 08:38:16
didn't notice metl had already posted the tip about using a gap in the floor.
Also Sorry For The Doublepost And...
#8219 posted by than on 2009/01/13 08:46:09
Monsterclip: Ffs
#8220 posted by anonymous user on 2009/01/13 09:26:02
trigger_monsterjump with low values - height 10, speed 10. if you want it killable, use the info_notnull hack.
#8221 posted by JneeraZ on 2009/01/13 11:14:10
"trigger_monsterjump with low values - height 10, speed 10. if you want it killable, use the info_notnull hack."
That's interesting. Can anyone think of why this wouldn't work? The monster might get stuck in a perpetual state of falling or something.
But
#8222 posted by than on 2009/01/13 11:51:15
monsters still go through their attack routine whatever state they are in I think. if they are being flung through the air I think they still attack.
Not 100% on that though.
#8223 posted by JneeraZ on 2009/01/13 12:26:30
The problem you'd have though, I think, is that the monster will never get the message. Sure, they'd be rejected by the jump trigger but that will never get them to change their route. They'll just run into the trigger forever, looking retarded.
Necros:
#8224 posted by metlslime on 2009/01/13 13:37:27
i think clip brushes in func_s do stop player movement. i'm pretty sure i tried that once, but it was a long time ago
clip brushes in funcs work correctly, as long as they are inside the bounding box of the visible part of the func. Quake (stupidly) doesn't bother doing collision detection against other entities when those entities are outside the visible part of the func.
Monsterjump
#8225 posted by ijed on 2009/01/15 02:39:08
Does work, I forgot that one.
I think I used it with 0 vert ~5 horiz once.
Does The Info_intermission (?)
#8226 posted by RickyT33 on 2009/01/21 22:32:30
or whatever it is (the cameras for the scores between levels), er, do they take up room in the signon buffer?
Buffers For Shoes
#8227 posted by Preach on 2009/01/21 23:32:40
The client doesn't know about them, because they don't have a model set, so they aren't transmitted between levels.
If you are having trouble with your signon buffer being too large, the easiest thing to reduce is the number of entities which have a model set at time zero. Static entities count towards this limit, but the only thing you can do about them is remove some.
It's worth noting that things which have modelindex != 0 do in fact count towards this total. I managed to discover this when I tried updating the quoth code to use this code for teleporting monsters:
http://inside3d.com/showtutorial.php?id=171
The line of code which hides the monster:
self.model = "";
is not enough to stop the monster being sent in the signon buffer, and consequently ne_marb started overflowing. If anybody uses that tutorial, it is advised to add
self.modelindex = 0; just after that, a trick which triggers already use.
I suspect though that the map which is hitting the limit is already a quoth map, and so you can't code your way out of it. In which case, I can suggest one or two entity hacks which might save you...
The first suggestion I have is to make some entities spawn later than they usually would, so they are sent in an update after the signon buffer. The candidate I'm thinking of is a func_wall, which is relatively safe to use. But be warned that it should not be done in the following cases:
* If anything is going to spawn on top of the func_wall
* If the func_wall is using an external model in quoth which wouldn't be spawned otherwise
* if there's some other reason that it needs to be in place from the start - don't worry about the player seeing it
Ok, so that's the plan, here's how we do it:
Change the classname of the func_wall to a info_notnull (hello old friend!). Give it the following keys:
self.nextthink = 0.2;
self.think = func_wall;
Can you guess what it does? It uses the fact that classnames are also functions ( http://www.celephais.net/board/view_thread.php?id=4&start=7981&end=7981 ) so that the func_wall initialisation is actually run as a think function just after the signon buffer is sent.
If you can't get enough mileage out of doing this on func_walls, you could look at doing it to other entities. Complex things like doors are probably a bad idea because the parts of the door have to link. You have to be careful that the spawn function doesn't do anything like precaching sounds or models, and you can't do it with static entities - they MUST be in the signon buffer.
Quoth is a bit more forgiving in this regard, as long as the model required has been precached by something during worldspawn, the actual attempt to precache it again later on is suppressed by the code. So you could do this trick on monsters for example - but then why not just give them the silent and teleporter flags, and teleport them in a second after the map spawns? It avoids using a hack to do it, and that bug about the signon buffer above has been caught and fixed ;-).
Preach
#8228 posted by RickyT33 on 2009/01/21 23:40:22
You are a legend, but allas - 'tis too late!
No fault of your own though, obviously, its just that i have weakened and folded....
Preach
#8229 posted by necros on 2009/01/22 01:59:05
the stuff i've seen you do without modifying a single line of code is godly.
been meaning to say that for a bit now...
#8230 posted by JneeraZ on 2009/01/22 11:31:01
I agree and echo the sentiment, Preach. Your level of knowledge in the area of Quake is incredible. Thanks for always being so willing to help with questions and being so eager to share.
Heh
#8231 posted by Preach on 2009/01/22 19:48:56
See, I've been meaning to make a post on exactly the opposite thing - how to code things in such a way to defend against mappers hacking them.
Would people like to read that, or is denying people the fun of entity hacking just too much?
#8232 posted by JneeraZ on 2009/01/22 19:50:53
I guess it depends. What would be your reasoning for preventing hacks?
Versioning
#8233 posted by Preach on 2009/01/23 00:47:57
If you are making a mod which lots of mappers are going to use, but which isn't final - you may release a new version of this mod in the future, then you have to worry that all of the old maps will work in your new version. In an ideal world all you would need to maintain is the advertised features in your documentation.
Of course, the documentation of what you intended is never finished, and it can be hard enough just maintaining things as you add new code (see: quoth 2.0). If people start using "unadvertised features" in maps, then you can get stuck. You would like to make some change to something you thought was internal, but that will actually break the hack in some existing map.
So I guess the message here is that performing hacks in maps for id1 progs is basically safe because there won't ever be another patch for quake, 1.08 is the end. Since it's going to be unchanging, you can get away with a lot more. With a mod that might in the future. With a mod that might come out with a new version, you probably should colour inside the lines for the most part.
In my defence for suggesting the func_wall trick, it is actually surprisingly hard to break with a mod, since the features it uses (think, nextthink, classname) are all hardcoded engine behaviours. The only thing you could really do to wreck it is change info_notnull to set think/nextthink(which seems pointless for an entity designed to do nothing) or change func_wall to do something that isn't safe after worldspawn like precaching things. So I think it's safe to say that will work in future Quoth versions.
#8234 posted by JneeraZ on 2009/01/23 01:01:07
Oh, honestly, I think you're off the hook there. I know about best intentions and all but if someone is leveraging a bug or a hack in your mod that you haven't documented and that breaks in the next version - so sorry, but oh well.
That's not an unreasonable position to take. Use the documented features only or risk getting burned. That's totally fair.
And, really, I'd rather have the freedom that the hacks provide rather than mod authors going through the work to lock everything down.
Yeah Preach - You Shouldn't Worry About It
#8235 posted by RickyT33 on 2009/01/23 01:11:57
because the person who is making the dodgy hacked map has a copy of the original progs he was using anyway, so if a later version breaks the hack then the player/mapper just has to roll back his version.
And you guys have catered for that by releasing the individual parts of quoth, upgrade by upgrade...
Defending Against Hacks
#8236 posted by Preach on 2009/01/24 01:44:21
It's reassuring to hear that, I'll worry less about people hacking. As a future warning, don't hack anything to do with path_corners in quoth, they don't work like they used to in quake, and they are going to change...
Even so, I'm gonna post how you do it anyway, because at the bottom there are two alternate applications of the ideas. And also because the second way in here is a really cool trick that I've never seen anyone post about before.
So if you do want to defend against a hack, what can you do? Well, to my knowledge there are three ways of defending against things, from the very specific to the very general. Even if you don't think you'd want to actively prevent a hack in your code, you might find some useful information at the bottom of the post about making entities more friendly to modification while maintaining sensible defaults.
If you are concerned about somebody putting an unhelpful value in one specific fields for a specific entity, then the way to prevent it is simply to set that field during the spawn function to a correct value. For example, if you have a monster which gets enraged after firing 10 missile attacks, and you count the shots fired so far in self.shotcount, you probably don't want people to be able to set .shotcount to 10 so that the monster is enraged straight away, so you can add
self.shotcount = 0;
in the spawnfunction. Although it sounds like a trivial thing there, you can prevent people from giving your entity a use function(assuming it normally lacks one) with
self.use = SUB_Null;
You could even preempt people making your entity shootable and killable by forcing
self.takedamage = 0;
self.th_die = SUB_Null;
...although some people might call that paranoid. This method is in a sense exclusive, you chose which fields you are going to prevent being set. If you start doing too much of this stuff, you should instead look at the third suggestion.
The second idea is one I've never really used because the idea only just came to me after discovering a light.exe feature. Rather than preventing people from custom-setting one field in a particular entity, this one lets you prevent a person setting the field in ANY entites. A good example of something that might warrant this protection is .super_damage_finished . The super_damage_finished field makes an attacking entity do quad damage so long as the map time is less than its super_damage_finished value. It's a bit of an ugly hack using that to get monsters with deadly weapons.
The fix is to rename the field to begin with an underscore, like _super_damage_finished. Any field which starts with an underscore gets stripped from an entity as it is loaded by the engine. This is intended so that light tools could read extra fields on lights, which had sensible names preceeded by underscores. These fields then wouldn't cause warnings if the qc omitted their definition. What we are doing is flipping that, creating a field which is only used by the qc and never from the map, rather than always by the map(via tools) and never in the qc.
For those of you who are c++/java fluent, I've come to think of this trick as creating public and private fields on entities(with respect to the map loading).
Defending Against Long Posts
#8237 posted by Preach on 2009/01/24 01:45:35
If you want to go further in the other direction, protecting almost all of the fields on a specific class of entity, then there is a pattern you can use in your spawn-function:
void() func_protected =
{
local entity template;
precache_sound ("misc/whine.wav");
template = self;
// we spawn a new entity with all fields blank
self = spawn();
self.classname = "func_protected";
//at this point you copy across all the fields you do want to inherit from the mapper
self.model = template.model;
self.health = template.health;
//...
//then you perform the setup on self as you would expect, eg:
setmodel(self,self.model);
//...
//finally, get rid of the template, since it is no longer needed
remove(template);
}
This gives you complete control on what can be set on your entity.
Although you may not see the need to do this for the reason of protecting an entity, there is a related construction which is more useful. Suppose you have a mod where several "rounds" of a game are played without the map restarting, but you want to reset the arena between rounds. How do you handle resetting something like a breakable wall, which may or may not have been destroyed during the round?
Method 1 would be to have a reset function which desperately tries to reset to zero all of the fields which might have been changed during the previous round on the wall. If it was destroyed, then the model field has probably been cleared, so you will need to store that information somewhere else, and you'll need to recall it's starting health from .max_health, and there are tons of things that could go wrong.
Method 2 is to use adapt the func_protected example above. The original entity placed by the mapper remains entire unchanging for the whole game, and we call this the "template". We split the above spawn function into two parts:
- the bit which precaches all the resources, which will run at worldspawn
- the bit which makes a new entity, copies the required info from the template, and sets it up
The latter function is called every time a new round starts, after the entity from the previous round has been removed. You should of course delete the line which removes the template from this version of the function!
(for c++/java people, this is a quake kinda way for doing the factory paradigm)
Finally, the flip side to the first method of protecting things(one field for a particular entity) is how to make a field customisable while still having a sensible default. Here are some methods for making the health of a shootable func_crate alterable (default:45), from the most common to the most bizzare:
if(!self.health)
self.health = 45;
This just takes the case that the mapper has set nothing, and makes it 45. We could fairly easily improve this to also perform a sanity check for negative health:
if(self.health <= 0)
self.health = 45;
We might instead decide to add whatever value of self.health is set by the mapper to 45.
self.health = self.health + 45;
This will still maintain the default at 45, but it's probably less sensible than the above methods in this case, as it would be confusing. There might be cases other than health where it would be a more sensible way.
WTF, You Double Agent!
#8238 posted by negke on 2009/01/24 10:07:57
First you lead us to the dark side of the progs, now you advertise methods of preventing the use of hacks... I can't map without them!
But yeah, mod/version conflicts are a potential problem indeed. Take the differences in model/precache handling in Quoth 1 and 2 for example. I had to come up with a crude way of progs detection in my 768 map in order to make the backpacks in the end arena appear correctly in each version.
Didn't You Understood ?
#8239 posted by JPL on 2009/01/24 11:32:28
Preach is working for an antivirus program provider company: those guys are hackers one day, and the other they sell you the latest update of their tool... swindler !!!
#8240 posted by anonymous user on 2009/01/27 16:48:58
is it possible to teleport weapons in ID1?
|
|
You must be logged in to post in this thread.
|
Website copyright © 2002-2024 John Fitzgibbons. All posts are copyright their respective authors.
|
|