Save baddie gain?

I can guess what Beholder was thinking when he made Downsider, “Now THIS is going to make Spooon go crazy!”

Hi!

Wow, it’s been a long long time since I’ve done this. I will do my best, but I will have to keep the code to pseudo code, and the concept explaining to hand waving…

When you say save style baddie, I assume you are referring to using the save[] variables associated to an NPC? Well, how much do you actually know about creating a baddie using these variables?

Essentially, you might use this style to create a “lagless” baddie. The built in baddies suffer from lag because all the code runs on the first players machine, and then x, y coordinates are sent to all other users. Unfortunately, to look smooth, these coordinates need to update 20 times per second (the fram rate of graal.) Even on high speed internet you can expect transfer times of 40 to 400ms or more depending on the geophysical distance the data needs to cross (ie: playing a client in California, connected to a server in Germany…) Add to the coordinates information about what the NPC is doing, or looks like, and you end up with a lot of very time sensitive data that just isn’t going to match up on everones machine.

If you want 20 updates per second, that would mean a maximum allowed delay of 50ms. Hardly achievable except on LAN. So “save style” baddies are a way to reduce the amount of information neccesary to create a nice looking baddie.

When you think about what makes a fight frustrating, I would suggest it is the inability to see what is hitting you, and what you are hitting. Essentialy, if I see my character get hit by a baddie, I expect to take damage. If I don’t see that happening, I had better not be damaged, or the baddie will seem flawed. Of course, the opposite is true when attacking. If it appears I have hit the baddie with my sword, it had better take some damage, if it doesn’t the baddie will seem flawed again. So what’s really important here is perception. Each users shouldn’t really care about where the baddie is on the other players screen, just where it is on their own screen. This is much more complicated when fighting baddies which require positioning tactics, but that is for another post…

I just described why updating the position of a NPC 20 times/second doesnt work, so instead of sharing data that changes extremely often (like it’s position) lets share something that changes much less often (like it’s destination.)

That is where the save variables come in. If I use save[0] to store the current target players id, then on each client machine I can use the showimg command to show the baddie closing in on the coordinates of player 1. To player 1, the baddie will appear to be getting closer to his/herself, while to everyone else, the baddie will seem to be getting closer to player 1. It doesn’t matter if the coordinates are a little off, because each player will have the NPC drawing the images getting a little closer to player 1.

As I mentioned, the coordinates may be a little off for each player, but that doesnt matter because the important thing is that each player is only damaged if the baddie appears to hit them locally, and the baddie is damaged if the player hits them locally. So, in pseudo code, we can do something simple, like if (LocalPlayerIsHit) {damage LocalPlayer}, if (LocalPlayerHitsMe) {take damage}. We don’t have to worry about for looping over all the players and stuff…

So as for assigning xp/rupees etc whatever you like to the last person who hits, I imagine you could do something like if (LocalPlayerHitsMe) {save[1] = player.id;} then later on, when the baddie is dead and assigning rewards if (dead && player.id=save[1]) {player.xp ++;}

First off, you really don’t want to be using showimg for your baddy. That will cause tons of trouble with hit detection.

What you want is each baddy to be its own NPC that uses a gani to display its animation. Doing this will allow smooth animation for the baddy, as ganis are clientside animations.

Hit detection will be a little more tricky. The first thing you want to do is specify the dimensions of the baddy with setshape. The client will use these dimensions when determining if the baddy got hit or not by your sword.

Now, the rest gets very tricky, and is the reason why we use the save[] variables. In NPC programming, each NPC’s script is run independently on each player’s computer. That means for every player in the level, they are all running their own copy of the baddy’s script. The only difference is that the level leader is the only person with the ability to run timeouts or loops. The NPC flag isleader returns true if the script is being run on the client who is the level leader.

Now, the only way to synchronize the NPC with all the players in the level is to use the NPC’s various properties. If a client makes a change to one of the NPC’s properties, that change is sent to all the other clients. These are things like the NPC’s animation, position, health, save[] variables, or string parameters. So, the question is, how do I make the NPC take damage when I hit it with my sword?

Naturally, if you adjust the NPC’s health stat, it gets propagated to the other clients. But what if you want the NPC to have a “knockback” effect? The solution is to make sure that all the movement code is executed on the level leader’s machine. If you hit the NPC, you set one of the save variables to 1, and another to the amount of damage you did. The level leader will see that the “was hit” save variable was set to 1, so they will be able to apply damage and a knockback effect.

This is the essence of save[] variable programming of baddies. You are delegating one computer, the level leader, control over the baddy. It makes things a lot simpler.

Unfortunately, there is no way to make smooth movement for the baddy without an npc-server to issue server-side move commands. The best we can do is make sure the baddy works reliably across all machines, which is what using save[] variables accomplishes.

I still remember when you were testing the move command to see if it would make things smoother. “What the hell? This still moves like shit.”

Yeah, I figured out the problem. If used on an npc-server, a server-side move command will be sent to the client. Then, when the client updates the npc’s position, because the client is in server-side mode, it won’t send the npc’s positional packets back to the gserver.

Since we don’t have an npc-server, the client sees the move command and moves the npc. Since the npc’s position is updating, it then sends the npc’s position normally, like if you were to manually update the npc’s x/y position. Which results in the same lame choppy movement.

Just to note, move has a cache mode that apparently helps to smooth out that choppy stuff. Don’t know if you tried that out.

S’what we were just talking about ;D Move doesn’t do the “smoothing” without an NPC-Server, else it just sends the choppy 0.5’d co-ords to others.

Well I meant there is a mode you put in one of the parameters that tells move to cache the movement, thus making it smooth on the clientside between updates. The result, however, is not-so-accurate positioning of the NPC(which defeats the purpose, in my opinion).

If this is what you meant though, than oh well!

Cache just means it can store a few more “moves” before completing it’s route o_o

[quote] - 1: movements will be cached, the previous movements
will only be finished when the cache is too large
(distance to go >5);
this caching can be used on server-side npcs to
make the movement look like non-laggy even when
there are little delays sometimes[/quote]
I’ve used it before on the official and it does indeed smooth things out, but like I said it ends up with each player getting their own positioning, and thus, inaccurate.

Dunno how this will work without NPC-server, but it sounds a lot like the problem you guys were having with it not updating frequently enough.

When used server-side, move will send a special “move” packet to all of the clients that see the NPC. All the clients will then see the smooth movement. When run clientside, move is only run on the machine that executes the move. All other clients just get the standard 0.5 tile x/y updates, the same type they would see if the NPC’s x/y values were modified manually.

Hi!

I used to code for the player world Shaded Legends. I indeed had several baddies wich moved smoothly using nothing more than local timeouts and save variables. Of course, this new server side scripting sounds great…

So is there a server side NPC controller that we can take advantage of on the gs2emu? Otherwise showimg and showgani may be your only option. Of course Nalin is correct that hit detection will be an issue because images do not have built in hit detection. You will need to run your own hit detection on each client. Fortunately, you only need to detect actions from the current player. Sadly, this is basically incompatible with custom weapons… so if that is a requirement you will need to try something else.

Why do you always start your posts with “Hi!”

All NPCs are clientside, however their property changes are sent to other players.
There is no //#CLIENTSIDE, yet there is no serverside scripting. Such is the enigma of not have an NPC-Server.

Why do you always finish your posts with a graalian who does not know boomerangs return to their starting point? I am simply being friendly. I have actually only started my first post / thread this way.

___Merged doublepost__________________

I guess that means there is no NPC server, but that’s fine. I did all my coding without such a concept…

The leader acts as a server of sorts for scripts, usually.

If you want it to be smooth, you have to predict it’s position on each client that’s not the leader, by giving sufficient information in save variables (X, Y, XOffset, YOffset, target, action). XOffset and YOffset are used to remedy the ugly half-tile accuracy. You’d then use a showani to render at the predicted position. Nalin, however, is correct in saying that the hitbox will lag behind, since we’re using extrapolated data. The way to remedy this is to use interpolated data instead. You need an array of “buffer” save variables, delaying it by two or three frames. The more frames delayed by, the better your interpolation, but at the cost of a little artificial latency. Then, you’d interpolate between the frames acquired and should have something that looks smooth. However, your client will now have the hitbox now in front of the actual rendering… To remedy this, you need to store at least 20 frames of positional history in an array. You’d then use an extrapolated timevar to, when the player slashes, determine at what position the hitbox should be on both the client and leader. Also, prediction errors should be smoothed to remain as natural looking as possible.

___Merged doublepost__________________

Oh yeah, with that method, or with any method worth it’s balls for hitbox and collision detection, you have to write your own damage system and can’t use default washit variables.