ID:160611
 
I was wondering if it's possible to create an NPC block (Which is if you don't know,an invisible wall that stops my Monsters from wandering), which also allows projectiles to pass through it with out causing massive amounts of errors or not allowing the projectile through at all.

If anyone can help me, please do.
You can override a turf or area's Enter() proc to disallow NPC mobs to move through it by returning 0 when they try. Or, you could change your AI so it doesn't attempt to move to these areas in the first place.
In response to Kaioken
Kaioken wrote:
You can override a turf or area's Enter() proc to disallow NPC mobs to move through it by returning 0 when they try. Or, you could change your AI so it doesn't attempt to move to these areas in the first place.

The last is probably the best because it's not as bad as where you have a piece of land and monsters/npcs are just trying to walk onto it for like 15 minutes until they finally turn and try a new spot.
In response to Swimchao
Personally, I would use the former. Keeping code under what it mainly relates to makes it nice and organized.
In response to Glarfugus
Glarfugus wrote:
Personally, I would use the former. Keeping code under what it mainly relates to makes it nice and organized.

Actually, the latter make a lot more sense. Why would you waste extra cycles on the turf/Enter(), when you can just have the AI not even try?

Former: I wonder if its okay for me to put my hand on this very hot stove-top burner. Ouch! No its not, moving on.

Latter: That very hot stove-top burner is bad, lets move on.

See? =)
In response to K'ros Trikare
K'ros Trikare wrote:
Former: I wonder if its okay for me to put my hand on this very hot stove-top burner. Ouch! No its not, moving on.

Actually, it may even go like this :


Former: I wonder if its okay for me to put my hand on this very hot stove-top burner. Ouch! Let me try again.. OUCH! Err, one more time. (burns) Moving on...

^ stupidity of AI when programmed wrong.
In response to Andre-g1
Andre-g1 wrote:
K'ros Trikare wrote:
Former: I wonder if its okay for me to put my hand on this very hot stove-top burner. Ouch! No its not, moving on.

Actually, it may even go like this :


Former: I wonder if its okay for me to put my hand on this very hot stove-top burner. Ouch! Let me try again.. OUCH! Err, one more time. (burns) Moving on...

^ stupidity of AI when programmed wrong.

Too true =D
In response to Glarfugus
But it's actually the former that has the code under /turf/Enter() and not under the actual object it relates to (eg /mob/monster), so that's quite weird. For the latter you modify your AI routine itself, which is obviously related to your monster.
In response to Kaioken
Putting code that keeps an NPC from entering an area under /mob/monster would be writing the function of said area under /mob/monster. It's really a matter of personal preference, I just like the barrier knowing it's supposed to block something rather than the monster telling the barrier to block it.
In response to Glarfugus
Glarfugus wrote:
Putting code that keeps an NPC from entering an area under /mob/monster would be writing the function of said area under /mob/monster. It's really a matter of personal preference, I just like the barrier knowing it's supposed to block something rather than the monster telling the barrier to block it.

You're looking at it from the wrong way.

Why bother with the barrier at all, if you can just have your monster not even look at the barrier? See my burner example. :)

Haha, yay logistics.
In response to K'ros Trikare
How would the monster know that isn't supposed to cross the area without checking first, though? I honestly can't think of a method that would be more robust/efficient than just overriding the Enter() proc.
In response to Glarfugus
Here goes a little example I made up.

mob/NPC/proc/Walk()
while(src)
for(var/T in get_step(src,src.dir)
if(istype(T,/area/nonpczone)) return
else if(!T.density)
src.step_to(src,T,0) // not sure if used correctly or if there is a better proc for that.
sleep(5)


That's a lot better than overriding the Enter proc in my opinion, it would just be a useless override when you can just make a simple change on the NPC moving proc.
In response to Andre-g1
get_step() returns a turf and the return statement ends the procedure so you have to start it again. T would never be type /area/nonpczone, therefore the NPC would never by hindered by such an area. Whereas overriding /area/nonpczone/Enter()...

area/nonpczone/Enter(mob/NPC/M)
if(istype(M)) return 0
..()


You could also edit that code to make the monster walk away or something of the sort.
In response to Glarfugus
I meant continue where that return is.. Oh well.

Anyways, that would make the mob still TRY to enter it. But only to be denied. However, if you change the NPC's walking proc, you can make it not even CONSIDER trying to move there.

That was my point originally.
In response to Glarfugus
Glarfugus wrote:
Putting code that keeps an NPC from entering an area under /mob/monster would be writing the function of said area under /mob/monster.

Or, if you look at it the other way, you're writing the function of said /mob/monster under /mob/monster. =P But that doesn't really matter.

It's really a matter of personal preference, I just like the barrier knowing it's supposed to block something rather than the monster telling the barrier to block it.

You're missing it, though, it's not only preference. The 2 results are inherently different. If you don't alter your AI logic and simply override Enter(), your AI logic will attempt to move even to restricted locations, and will think it succeeds in movement but in fact the Move() call will fail, and it will keep attempting to move because it doesn't account for the restricted area. It would in fact break your AI under certain situations*, the only advantage is that that method is simpler to use; you only override the proc with simple code, and you can use the built-in walk() series procs that indiscriminately attempt moving through all turfs (disallowing custom pathfinding).
Then you've got the other, much cleaner way: if an unrestricted tile is in the way, don't even attempt moving there, and instead of helplessly trying and getting blocked, continue with the rest of the AI routine. eg: if the monster can use a ranged attack (and you desire the monster block tiles not to block projectiles), then attempt to use it, otherwise if there's another enemy in range, instead of trying to reach the one that's unreachable, intercept the one that isn't blocked, etc.

*: Consider this situation: 2 (or more) players are intercepting one monster. One of them sits without moving just after the edge of the monster blocker area, 2 tiles away from the monster, and the other sits 3 tiles away from the monster. With the Enter() method, the AI will keep trying to move towards the unreachable player and get blocked instead of ignoring him and attacking the other player. Of course, this is easily exploited as the monster is a sitting duck; just entering the monster's range behind a blocker tile can possibly render the AI useless with this method.

How would the monster know that isn't supposed to cross the area without checking first, though? I honestly can't think of a method that would be more robust/efficient than just overriding the Enter() proc.

What do you think the Enter() proc is for? Checking all the same (and the return value is based on the results, which you've forgot in your code BTW). Neither is checking all that inefficient, but better functionality can cost a little more, naturally.
In response to Andre-g1
Let's say the NPC has several procedures for movement - we'll use Wander(), Chase(), and Teleport() for the sake of example. Wander() is self-explanatory; Chase() selects a client-controlled mob, stores it in a variable, and chases it until it runs out of view; Teleport() is for NPCs that make like that little bugger Abra from Pokemon and disappear if you get too close. You would have to check for /area/nonpczone in all three, which is inefficient. /area/nonpczone/Enter() would be called in all three cases, which means you only have to code it once.
In response to Glarfugus
Glarfugus wrote:
Let's say the NPC has several procedures for movement - we'll use Wander(), Chase(), and Teleport() for the sake of example. Wander() is self-explanatory; Chase() selects a client-controlled mob, stores it in a variable, and chases it until it runs out of view; Teleport() is for NPCs that make like that little bugger Abra from Pokemon and disappear if you get too close. You would have to check for /area/nonpczone in all three, which is inefficient. /area/nonpczone/Enter() would be called in all three cases, which means you only have to code it once.

So you prefer the NPC's bumping into invisible walls just for the hell of it ?

And why have Chase() and Wander() in separate procs ? They can just be merged into one. Hell, even teleport() can be in it, since it doesn't do much. It's just a matter of else-if and they can be easily merged into one proc.
In response to Andre-g1
1. As stated, you can set /area/nonpczone/Enter() to move them in a different direction if called.

2. It'd be rather sloppy to merge it into one procedure, and even so, you would still have to run the check several times.
In response to Glarfugus
Glarfugus wrote:
You would have to check for /area/nonpczone in all three, which is inefficient.

You'd check it a total of one time when the NPC either chooses or chases a target, preventing further unnecessary movements if the monster would be blocked anyway, so it is more efficient, but you're not making any sense regardless. How is doing an operation in different places inefficient? It isn't. And as I've said, this method actually prevents unneeded operations, including but not limited to the infamous "keep constantly attempting to move but be blocked each AI iteration" phenomenon.

/area/nonpczone/Enter() would be called in all three cases, which means you only have to code it once.

Exactly, that's your only supposed benefit, the code, not the efficiency. But you could port your custom check over to a proc as well (...just like there's the Enter() proc) and only have it appear once in the code.
In response to Glarfugus
Efficiency isn't really the issue here as far as I can see.

Clarity of code and coupling between the mob and turf is where I see the problem. Suppose a bug develops somewhere in the NPC's AI. If there are fragments of the NPC's AI in the turf code you now have to check two places.

It's perhaps hard to see Andre-g1's point with this trivial function, but in a larger project code fragmentation can become an issue.

Good Object Oriented design consists of a number of isolated objects. The communication should be very simple between these objects. In your design, there is a two way 'conversation' between the mob and the turf.

E.g:
Mob - Can I enter you?
Turf - No, you should turn around.

as opposed to:

Mob - Can I enter you?
Turf - No.
Mob - Guess I should turn around.

In the first example the Mob and Turf suffer from control coupling. Control of the mob's movement is passed to the turf.

In the second example, the communication between the objects is kept to a minimum. The turf needs no knowledge of the working of the mob's AI, it just needs to decide if it will allow the mob to enter or not.

When two objects are dependant on each other, like in your design it is known as 'coupling'. Coupling == bad OO design, and increases the difficulty of maintaining your programs.

Edit:
Hmm... on further thought I may have misunderstood the disagreement here. It's actually Glarfugus who's promoting the better design in my opinion :)

Edit (more rambling):
On the topic of 'why should the mob try to move to the barrier and get rejected, when it can just decide not to try it'

Consider a game where there are three types of turfs. One normal type, where anyone can enter. One type where only one mob can stand at a time. And one turf where people can only enter if it contains a magic item:

Scenario #1 - Mob decides which barriers to test:

Mob looks at Turf, wondering 'Are you a normal turf?'
Turf is not a normal turf.
Mob looks at Turf, wondering, 'Oh well are you a one-person-at-a-time turf, and is there somebody standing on you?'
Turf is not a one-person-at-a-time turf.
Mob looks at Turf... (well you can see what I'm getting at.)

Scenario #2 - Mob uses the Enter() Interface so it only has to ask one question:

Mob: Can I enter you?
Turf considers its current state and decides whether Mob can enter
Turf: No.
Mob: Oh better record that I've tried you and try somewhere else.

In scenario #1, adding extra conditions that may prevent a mob from entering a turf will involve editing the mob's AI as well as adding the actual turf.

In scenario #2, adding extra conditions will just involve adding an extra turf that can answer the question 'Can I enter you?' The mob doesn't need to know why it's being blocked, just that it has not been allowed.

Edit - Some links that may clarify OO Design and the problems of coupling:
Coupling
Data Hiding
More on coupling
Polymorphism (yay big words!)
Page: 1 2