Server Help

Bot Questions - Detecting if pilot is in certain coords

Anonymous - Wed Jul 07, 2004 9:00 pm
Post subject: Detecting if pilot is in certain coords
How do I make the code so that it detects if a pilot is in a certain area and then does something? I tried some of the examples on the tutorial website but I just couldn't get them to work.
CypherJF - Wed Jul 07, 2004 10:11 pm
Post subject:
Spawn.cpp::

Quote:
case EVENT_PlayerMove:
{
Player *p = (Player*)event.p[0] //provided by catid.

if (p->tile.x == # && p->tile.y == #)
{ /* they are on tile. */ }

}


I think those are the correct variables for the struct :/ ... The tutorial had some parts missing; some explinations could be in better detail.. It's slightly outdated, but not too bad. You can get most general jists from it... Just keep askin here, if you continue having problems icon_smile.gif
50% Packetloss - Thu Jul 08, 2004 12:52 am
Post subject:
yep,

if(p->tile.x >= x1 && p->tile.y >= y1 && p->tile.x <=x2 && p->tile.y <=y2)
{
}

//(x1,x2)--------
//|
//|
//|--------------(x2,y2)
Mr Ekted - Thu Jul 08, 2004 12:33 pm
Post subject:
Detecting a specific tile may be bad. From one update to the next, the ship may jump across a tile without ever "touching" it. Unless you plan on doing your own dead reckoning?
Underlord - Thu Jul 08, 2004 12:37 pm
Post subject:
almost exactly from the tutorial

Code: Show/Hide

// functions go in the DLL "import" section
bool closeto(Player *p, int x, int y, int tolerance) {
    return (abs((p->tile.x) - x) < tolerance) && (abs((p->tile.y) - y) < tolerance); }

inline int abs(int n) {
    if (n < 0)    return -n;
    else        return n; }

case EVENT_PlayerMove: {
            Player *p = (Player*)event.p[0];

            int radius = 30;

            if (p->ship != SHIP_Spectator)
                if (closeto(p, 512, 512, radius)){
                   // do action here
                }

Dr Brain - Thu Jul 08, 2004 12:47 pm
Post subject:
Here is a circular one:

Code: Show/Hide
bool closeto(Player *p, int x, int y, int tolerance)
{
    int deltax = p->tile.x - x;
    int deltay = p->tile.y - y;
    return (tolerance * tolerance >= deltax*deltax + deltay*deltay);
}

Mr Ekted - Thu Jul 08, 2004 3:28 pm
Post subject:
Underlord wrote:
almost exactly from the tutorial


Every known C/C++ system has abs as a basic function/macro. There's no need to redefine it, especially when it requires the use of 2 returns. icon_sad.gif
50% Packetloss - Thu Jul 08, 2004 7:13 pm
Post subject:
you could use the distance formula too, to measure the distance between a point and a player then see if they are within the distance you want
Mr Ekted - Thu Jul 08, 2004 7:40 pm
Post subject:
50% Packetloss wrote:
you could use the distance formula too, to measure the distance between a point and a player then see if they are within the distance you want


Yes, see Dr Brain's code above. icon_redface.gif
CypherJF - Thu Jul 08, 2004 9:00 pm
Post subject:
This would be a good FAQ question.
Underlord - Fri Jul 09, 2004 11:36 am
Post subject:
Quote:
Mr. Ekted - Every known C/C++ system has abs as a basic function/macro. There's no need to redefine it, especially when it requires the use of 2 returns.


Have to include math.h to get abs. The Dr Brain version looks better anyways.
Cyan~Fire - Fri Jul 09, 2004 7:15 pm
Post subject:
FFS.

Code: Show/Hide
int __cdecl abs(int);

Mr Ekted - Fri Jul 09, 2004 7:20 pm
Post subject:
Underlord wrote:
The Dr Brain version looks better anyways.


Anything with 2 returns can't be better by definition.
Anonymous - Tue Jul 13, 2004 9:52 pm
Post subject:
Ok I have a problem, I am using the x1, y1, x2, y2 method:

Code: Show/Hide
if(p->tile.x >= x1 && p->tile.y >= y1 && p->tile.x <=x2 && p->tile.y <=y2)


I made it so that it warps me when I get to the area specified. But it seems to warp me 2-3 times, though it seems like once in-game. How can I slow it down?
Matzke - Tue Jul 13, 2004 10:27 pm
Post subject:
damn i gotta try harder and learning c++, i dont understand a single thing u guys saying icon_razz.gif
Dr Brain - Tue Jul 13, 2004 10:53 pm
Post subject:
I don't know how you would solve that in merv, but the problem is that it's getting position packets from your old location. You may have already warped, but it doesn't see that for a few hundred milleseconds. That's plenty of time for it to send another few warpto packets.

In Java I would put the player's name into a HashMap with an timeout time. It'll only warp them again if they aren't in the map or if their timeout has gone bye.

I think the tags may suit your purpose, but it's been at least a year since I've worked with MERV.
50% Packetloss - Tue Jul 13, 2004 11:56 pm
Post subject:
The problem is solved by recording the player on a linklist or something else then deleting it when they exit the area. Look at my message bot, its on catid's site and it does the same thing kinda. The tm-baw does it another way, it records the player and then deletes them after 1.5 seconds.
Bak - Wed Jul 14, 2004 11:11 am
Post subject:
the problem is the client sends a few packets inside the area before it starts sending them outside.

A solution would be to keep track of the last time warped for each player and if it's < tolerance ignore it.

You could even use the evil player tag system catid made, let's see...

in spawns.cpp at the top, after #define UNASSIGNED 0xffff (not in a function) put:

Code: Show/Hide
#include <windows.h>
#define TOLERANCE 100
#define TIMER_TAG_INDEX 151561
#define X1 512
#define X2 520
#define Y1 512
#define Y2 520
#define WARPTO_X  450
#define WARPTO_Y  430


then in EVENT_PlayerMove put:


Code: Show/Hide

if(p->tile.x >= X1 && p->tile.y >= Y1 && p->tile.x <=X2 && p->tile.y <=Y2)  // Player is in region
{
   int curTime = GetTickCount() / 10 ;

   int lastWarpTime = get_tag(p, TIMER_TAG_INDEX);

   if (curTime - lastWarpTime > TOLERANCE) // player wasn't just warped
   {
      sendPrivate(p,"*warpto" + (String)WARPTO_X + " " + (String)WARPTO_Y);
      set_tag(p, TIMER_TAG_INDEX, curTime);
   }
}


That should do it. Of course make sure you change the #define values to the ones you want to use.

MGB: When I do "Preview" and I have two blocks of [code] it doesn't preview them both, only the first one. When I post both are shown, however.

EDIT: Updating to use centiseconds instead of milliseconds.
Mr Ekted - Wed Jul 14, 2004 11:58 am
Post subject:
You should probably initialize this tag for all players as they enter the arena to the current time.
Anonymous - Wed Jul 14, 2004 1:21 pm
Post subject:
Oh well, those methods seem very time-consuming or I just don't understand how to do so, probably because I didn't know anything about C++ until I started coding bots. So I will just try to modify TM_Baw so that it uses a .ini file with a different name.
Bak - Wed Jul 14, 2004 2:02 pm
Post subject:
what's confusing? It's copy and paste.

The get_tag returns 0 if it can't find a tag for the player... so unless GetTickCount() returns a number <= 1000 (this cooresponds to the amount of time since the system was started) he should be alright.

The only issue you might get is after the system is on 25 days where the integer variable will wrap around to negatives. Then new players may get warped more than once. I'll update the code to use centiseconds instead and it should solve this, as the value will always stay positive. Good catch Ekted.
Anonymous - Wed Jul 14, 2004 3:51 pm
Post subject:
I don't get the #define things. I will have several warps on the map, does that mean I have to do that define thing every time I create a new warp in different coordinates?
50% Packetloss - Wed Jul 14, 2004 5:02 pm
Post subject:
the #define is kinda like a message to the compiler. Only the compiler looks at it, this is how it works
#define TOLERANCE 100
the above defines TOLERANCE to mean 100, so if i do int bob= TOLERANCE; then bob with equal 100. The 1st part is the name of the value and the 2nd part is the value. You can define anything, not just use them as variables but as code.
#define SEXME sendPrivate(p,"umf")
you can look up uses on google, but they are helpful at times
Bak - Wed Jul 14, 2004 5:59 pm
Post subject:
ok your best option for multiple warp areas is to have a class/struct that stores the info for each rectangle and where to warp to and you can easily add and keep track of them. Confused? It's okay, the code isn't that hard.

on the top of spawns.cpp keep:

Code: Show/Hide
#include <windows.h>
#define TOLERANCE 100
#define TIMER_TAG_INDEX 151561


on the top of spawns.h, after #include "..\dllcore.h" but outside of any function/union put:

Code: Show/Hide
#include <vector>
using namespace std;

struct WarpRect
{
   int x1,x2,y1,y2,warpto_x,warpto_y;

   WarpRect(int _x1, int _x2, int _y1, int _y2, int _warpto_x, int _warpto_y)
   {
      x1 = _x1;
      x2 = _x2;
      y1 = _y1;
      y2 = _y2;
      warpto_x = _warpto_x;
      warpto_y = _warpto_y;
   }

   bool contains(Player *p)
   {
      bool rv = false;
      if(p->tile.x >= x1 && p->tile.y >= y1 && p->tile.x <= x2 && p->tile.y <= y2)  // Player is in region
      {
         rv = true;
      }

      return rv;
   }
};



the vector is so we have access to the STL vector class. It's pretty much an array(collection of anything) that can be of any size. using namespace std allows us to use vector without having to call it a std::vector every time. We'll store all of out WarpRects's in a vector.

Now in spawns.h in the botInfo class definition, on the line before "botInfo(CALL_HANDLE given)"
we put our defintion of the vector... then after the { 2 lines later we'll define our rectangles... so it looks like this:


Code: Show/Hide
vector <WarpRect> warpRects;

   botInfo(CALL_HANDLE given)
   {
      warpRects.push_back(WarpRect(512,600,512,600,400,400));
      warpRects.push_back(WarpRect(200,250,200,250,100,100));
      warpRects.push_back(WarpRect(10,20,10,20,1000,1000));
      warpRects.push_back(WarpRect(600,650,12,20,80,900));


Each rectangle is defined like this (X1,X2,Y1,Y2,warptox,warptoy)

you can have as many of these as you want. What the push_back is doing is just adding your item to the array(collection).

Ok! now we just go to event_playermove and check each warprect... sounds easy enough right? here's the code:


Code: Show/Hide
case EVENT_PlayerMove:
      {
         Player *p = (Player*)event.p[0];

         for (unsigned int x = 0; x < warpRects.size();++x)
         {
            if (warpRects[x].contains(p))
            {
               int curTime = GetTickCount() / 10 ;

               int lastWarpTime = get_tag(p, TIMER_TAG_INDEX);

               if (curTime - lastWarpTime > TOLERANCE) // player wasn't just warped
               {
                  sendPrivate(p,"*warpto" + (String)warpRects[x].warpto_x + " " + (String)warpRects[x].warpto_y);
                  set_tag(p, TIMER_TAG_INDEX, curTime);
               }

               break;
            }
         }
      }


You notice there is only one timer per player. This means they can only be warped one time per second (because tolerance is 100 centiseconds). So if you have him warp to another warp area, he won't get warped right way. If you need this feature just say so.
CypherJF - Wed Jul 14, 2004 8:17 pm
Post subject:
definately deserving a FAQ slot.
Mr Ekted - Thu Jul 15, 2004 3:37 am
Post subject:
Bak wrote:
The only issue you might get is after the system is on 25 days where the integer variable will wrap around to negatives. Then new players may get warped more than once. I'll update the code to use centiseconds instead and it should solve this, as the value will always stay positive. Good catch Ekted.


The old wrap. icon_smile.gif That is one of the first things I try to deal with when handling integer compares. It's especially bad with things like ticks in windows since they are unsigned, and people often try to subtract to compare to some expected range. I never subtract unless I know I set a base that IS relative to the value.
Bak - Thu Jul 15, 2004 10:15 am
Post subject:
so how do you compare to some expected range. I couldn't change the variable to unsigned long here because the tag's use integers, unless I didn't use tags or modfied them.

Do you do something like:

Code: Show/Hide
if (time2 - time1 < tolerance && time1 - time2 > -tolerance)

Mr Ekted - Thu Jul 15, 2004 1:55 pm
Post subject:
If you have a known base, like start_time = GetTickCount(), then at some point in the future, you can do GetTickCount() - start_time >= SOME_INTERVAL. This will always work even if the values wrap, because the difference also wraps.

0x00000001 - 0xffffffff = 2

If MERV tags are 32-bit ints, then you can simply cast ticks back and forth to unsigned ints. No change of bits is performed, just change of interpretation.
Bak - Thu Jul 15, 2004 2:38 pm
Post subject:
that's what it's doing. The problem is that if the tag isn't found it'll default to 0.

so curTime = -124114 and
lastWarpTime = 0

curTime - lastWarpTime is -124114 which is < 100 (tolerance).

but with centiseconds the value will never be negative, so the problem is solved.
All times are -5 GMT
View topic
Powered by phpBB 2.0 .0.11 © 2001 phpBB Group