Server Help

Bot Questions - help with creating a dll for mervbot

hellzlaker - Sun Mar 30, 2008 11:32 am
Post subject: help with creating a dll for mervbot
I am trying to make the bot to private message you this, "Hello <player name>" and <player name> = players name biggrin.gif

but how do i do that?

my guess it was
Code: Show/Hide
sendPrivate(p,"Hello "p);
but that didn't compile... anyone know how?
Samapico - Sun Mar 30, 2008 11:52 am
Post subject:
p isn't the player's name. 'p' is a pointer to a whole structure containing all the player's data. To get the name of the player, you have to type p->name. p-> lets you access each member of the player's structure. p->pos is a vector containing the player's position, for example.

I suggest you get some plugin examples and try to understand them. Even the empty command.cpp file has a line containing exactly what you need, the !about and !help commands are already coded in there.

Also, if you have no experience with c++, do some tutorials first; Understanding pointers, classes and structs is a big plus.
hellzlaker - Sun Mar 30, 2008 12:01 pm
Post subject:
i already got the default dll template and i know basic c++ (enough to code a dll) and i already made a bot that just says stuff when you say hi to it,

i just wanted to know how to make it say players name

and i tried
Code: Show/Hide
sendPrivate(p,p->name" hi!");
and it didnt work,

and also the p struct, in which source file is it?
Purge - Sun Mar 30, 2008 12:45 pm
Post subject:
Code: Show/Hide
sendPrivate(p, "Hello, " + (String)p->name);


That should locally PM a player 'p' "Hello, playername". p->name is stored as char name[20] I believe, so you may also manipulate it as a string.

You can find the player struct in player.h.
hellzlaker - Sun Mar 30, 2008 2:53 pm
Post subject:
thanks purge, thats exacty what i needed biggrin.gif
hellzlaker - Sun Mar 30, 2008 6:59 pm
Post subject:
i ran into another problem this is the code
Code: Show/Hide
sendPrivate(p,"I rolled a "(int)odice1", "(int)odice2", and a "(int)odice3);


and this is the compile error that VC++ gave me
Code: Show/Hide
1>c:\documents and settings\owner\desktop\programing\c++\a3 dll\tutorial\default\command.cpp(215) : error C2144: syntax error : 'int' should be preceded by ')'
1>c:\documents and settings\owner\desktop\programing\c++\a3 dll\tutorial\default\command.cpp(215) : error C2064: term does not evaluate to a function taking 0 arguments
1>c:\documents and settings\owner\desktop\programing\c++\a3 dll\tutorial\default\command.cpp(215) : error C2059: syntax error : ')'


any one help?
Cheese - Sun Mar 30, 2008 7:26 pm
Post subject:
you have to remember that
1+2+1+2+1+2+1=10
and
1212121 doesnt = 10

=/
Anonymous - Sun Mar 30, 2008 8:36 pm
Post subject:
oh so i have to add +, but how come like in cout u just do

Code: Show/Hide
cout<<"You rolled "<<number;

and not
Code: Show/Hide
cout<<"You rolled"<<+number;

Bak - Sun Mar 30, 2008 9:41 pm
Post subject:
the << operator for ostream does it for you like the + operator does it for you with the String class

if you really want to know what's going on look for String::operator+ in the mervbot source
hellzlaker - Mon Mar 31, 2008 4:46 pm
Post subject:
every time i fix one thing i get another problem ...

i tried this and it didnt compile
Code: Show/Hide
sendPrivate(p,"I rolled a "+(int)odice1+(string)", "+(int)odice2+(string)", and a "+(int)odice3);


also i tried this (it didn't compile either :S)
Code: Show/Hide
sendPrivate(p,"I rolled a "+(int)odice1+", "+(int)odice2+", and a "+(int)odice3);

Dr Brain - Mon Mar 31, 2008 6:13 pm
Post subject:
change your ints to strings.
Bak - Mon Mar 31, 2008 7:15 pm
Post subject:
and then change your strings to Strings
hellzlaker - Tue Apr 01, 2008 4:47 pm
Post subject:
Ok, i finished that bot and fixed all the problems but im going to do something else and i have few questions

is there a source code the rampage.dll or any one sprees? or atleast is theree a way to access thee spree from your dll, like if you get a spree 3:0 the rampage.dll does whatever it wants like says you got a spree, while your DLL gives you like a thousand points if you got that spree

how to access flag game, like if you win a flag game say freq 0 won the flag game and give them points (i dont want the existing flag.dll i want to learn how to make my own so thats why im asking)
Purge - Tue Apr 01, 2008 4:51 pm
Post subject:
I think 50% Packetloss created the rampage that prizes based on sprees. It should be out somewhere, a lot of zones use it.

For flag game stuff, check spawn.cpp in the plugin source file. There should be a flag event somewhere for victories.
hellzlaker - Tue Apr 01, 2008 7:10 pm
Post subject:
Is it open source? I want to get the source code or if any one can come with quick example how to make one like if you get 1 kill and thats it

also another thing i tried to do this code
Code: Show/Hide
            while (p->bounty!=(Uint16)neededbty||c->check("abortmission"));

            if (c->check("abortmission"))
            {
               sendPrivate(p, "aborted");
            }


it does compile but the bot just leaves game when this happens, and every time i make a while statement the bot leaves the game for some reason
Samapico - Wed Apr 02, 2008 1:09 am
Post subject:
that's pretty much an infinite loop you created there...

It just endlessly checks the conditions. But for the player's bounty to change, other parts of the code have to be executed.

What you want to do is put an 'if' statement that checks your condition everytime the bounty of the player is changed. You can catch that with the PlayerDeath event (the killer's bounty increased) and the PlayerPrize event (player grabbed a green)
Not sure of the exact event names, but you get the idea...


Usually, a while loop will look like:

while (condition)
{
//do stuff
}
You have to make sure that the 'do stuff' part can have an impact on the conditions... Else, you will get an infinite loop if the condition is true.
Maverick - Wed Apr 02, 2008 1:16 am
Post subject:
hellzlaker wrote:
is there a source code the rampage.dll or any one sprees?

Rampage 2.5 and Rampage 3.0 (with customizable spree messages) is available to download from mervbot.com.
Both plugins have source code included.
hellzlaker - Wed Apr 02, 2008 6:15 pm
Post subject:
Code: Show/Hide

Uint16 neededbty = 16;
            while (p->bounty!=(Uint16)neededbty||!c->check("abortmission"));
            {
               c->check("abortmission");
               p->bounty;
            }


I tried that and it still doesn't work and the bot leaves continuum when i run it

This is what im trying to do, bot check players bounty and keeps checking until its 30, and checks if player typed .abortmission
Bak - Wed Apr 02, 2008 8:52 pm
Post subject:
your model of how you think mervbot execution occurs is wrong. There is only one thread of execution that handles sending and receiving packets, updating the player bounty when appropriate, and running your code. If your loop runs until the bounty is changed, the bot will never get a chance to update the player bounty (as execution is stuck looping in your function waiting for it to change) or send/receive packets (which is why it disconnects, by the way).

Even if the player types .abortmission at some point, the bot can't receive that packet since it's again, looping in your function.
hellzlaker - Thu Apr 03, 2008 4:17 pm
Post subject:
ok but will i be able to do something like this

if player type !mission do the following:
wait until player collects 30 bounty and then say you beated the mission
or if player types !abortmission it cancells the "mission"

from what i think its impossible to do without a loop
Samapico - Thu Apr 03, 2008 4:55 pm
Post subject:
You have to think of it like this...

if a player types !mission, set a tag on him that indicates he typed it
Code: Show/Hide

//Tag of index 0 is for the Mission value
set_tag(p, 0, 1);


and with !abortmission, you can simply reset the tag to 0.

In the events where the player's bounty changes (playerdeath, playerprize), get the tag, if it's set to 1, check if he collected 30.

Actually, you could set the tag to the player's current bounty, so you would know what bounty he had when he typed !mission, if you want the mission to stop when he gets 30 bounty more. Might have a problem if it is possible to have a bounty of 0 though... You'd need to use 2 tags, one that just says if he's on a mission or not, and another that tells his bounty when he got on mission.

Have fun.


On a side note, these lines:
Code: Show/Hide
               c->check("abortmission");
               p->bounty;

Don't do anything... p->bounty only returns the player's bounty. It doesn't update it or whatever. The bot has to receive a packet before modifying that value.
c->check("commandname") only returns true or false depending if the current command fits or not the command you want. Then again, the function doesn't do anything.
You can always right-click on a function, and Go To Definition to see what a function does. If it only returns you something, it's useless to use it in a loop like that. And as Bak said, most loops are useless anyway.
hellzlaker - Thu Apr 03, 2008 8:45 pm
Post subject:
thanks samapico this helped allot ,nice quick tutorial biggrin.gif
hellzlaker - Fri Apr 04, 2008 5:48 pm
Post subject:
shit i got confused with all this, how does a tag exactly work? like is exactly index and data?
(Player *p, int index, int data)

and what do you mean by get the tag? like
Code: Show/Hide
if (set_tag(p,0,1)){}
?[/code]
Purge - Fri Apr 04, 2008 6:34 pm
Post subject:
Tags pretty much just mark a player for reference using an integer "int data" as defined by the "int index".

To set a tag, you have to use the set_tag(Player *p, int index, int data) function. To read/get a tag you have to use the get_tag(Player *p, int index) function, where you will be checking for "int data".

Example - Setting a tag when a player calls command !sneeze checking if they have not triggered the command beforehand:

spawn.h:
Code: Show/Hide

#define INDEX 2         // This is your "int index". Call it whatever you want.

command.cpp
Code: Show/Hide

if (c->check("sneeze"))
{
      if (get_tag(p, INDEX) != 1) // This checks to see if '1' isn't stored for this player, meaning he didn't call !sneeze before.
            set_tag(p, INDEX, 1); // This will set the player's tag to '1', meaning he is calling !sneeze for the first time.
}


To clear all tags from a player, use the function killTags(Player *p).
hellzlaker - Fri Apr 04, 2008 7:51 pm
Post subject:
i kinda get it just need to clear some things up ( divided into 2 steps so its easier to explain what i tried to say)
STEP 1
Code: Show/Hide
if (get_tag(p, INDEX) != 1)
this checks if INDEX doesn't = to 1 (we defined it to 2 before..) so it does the following

STEP2
Code: Show/Hide
set_tag(p, INDEX, 1);
by what i understand it doesn't change INDEX and creates a new int data which = to 1 so as i understand INDEX is still exactly the same so if someone !sneezes second time it will go to STEP1 and it will check if INDEX != to 1, and it wont since as i understood we did not change INDEX in STEP 1 ..

so by what i understand it wont do anything but i know I am wrong I just want to know why ?
Samapico - Fri Apr 04, 2008 8:17 pm
Post subject:
it's pretty much it... go check the Merv functions of get_tag and set_tag, might help you understanding.

When you get_tag, the code scrolls through all the tags you've set, and when the player AND the index matches, it returns you the current value of that tag (the data). If it doesn't find any tag for that player with that index, it returns 0 by default.
Bak - Fri Apr 04, 2008 10:07 pm
Post subject:
a player* is like a book
an index is like the page number
data is the contents of the page,

so set_tag(p,455,70) writes the value "70" on page 455 of player p's book.

to get the value on page 455 do
Code: Show/Hide
int value = get_tag(p,455);

Purge - Fri Apr 04, 2008 10:20 pm
Post subject:
Don't confuse #define with a standard definition like int i = 0. In the snippet I posted, #define INDEX 2 is saying that INDEX has 3 values; or using Bak's analogy, 3 pages. It is not the same as int INDEX = 3.
Bak - Fri Apr 04, 2008 10:26 pm
Post subject:
wat? are you sure purge?
Samapico - Fri Apr 04, 2008 11:57 pm
Post subject:
uh... no... #define INDEX 2 means that anywhere you put INDEX in your code, it is replaced by "2" before anything is even compiled.

For example, if I need 3 tags, I usually do something like:
#define TAG_SOMETAG 0
#define TAG_ANOTHERTAG 1
#define TAG_THIRDTAG 2

And I use these as index values.

And what purge said isn't true... last I checked, the tags is a linkedlist, not an array. Each tag on the linked list is a struct with Player* p, int index and int data.
Bak - Sat Apr 05, 2008 12:03 am
Post subject:
to drive the point home, you can compile
Code: Show/Hide
#define APPLE int main()
#define SAUCE return 0;

APPLE
{
SAUCE
}

Samapico - Sat Apr 05, 2008 12:45 am
Post subject:
in Mervbot, you can use

WHEN_COWS_FLY
{
//statements
}

for something that will never happen...
If I remember right, there is:
#define WHEN_COWS_FLY if(false)
somewhere in the code tongue.gif
Purge - Sat Apr 05, 2008 1:47 am
Post subject:
Meh, sorry about the bad info. This is why I'm premed and not computer anything.
hellzlaker - Sun Apr 06, 2008 1:10 pm
Post subject:
Bak wrote:
a player* is like a book
an index is like the page number
data is the contents of the page,

so set_tag(p,455,70) writes the value "70" on page 455 of player p's book.

to get the value on page 455 do
Code: Show/Hide
int value = get_tag(p,455);


wow bak now i get it, lol thats a perfect explanation no joke,


and don't feel bad purge icon_wink.gif
hellzlaker - Sun Apr 06, 2008 2:15 pm
Post subject:
Ok i get the tags now and made a bot with them that works just how do you do a code that if any point during game that event happens, then exectute other code

this is the code when i tried to make the bot and it works just the bot realizes you beat the mission only you type something to him

also here the mission is to collect 30 bounty

Code: Show/Hide
         // EASY MISSION BOUNTY HUNTER CODE

         else if (c->check("easymission:1"))  // start easy bounty hunter mission
         {
            if (get_tag(p,mission1)!=on)
            {
               sendPrivate(p,"You started an easy mission \"Bounty Hunter\" Type !abort:easy:1 anytime during the game to abort this mission");
               set_tag(p, mission1, on);
            }
            else if (get_tag(p,mission1)==on)
            {
               sendPrivate(p,"You already started easy mission \"Bounty Hunter\" Type !abort:easy:1 to abort mission.");
            }
         }

         else if ( get_tag(p,mission1)==on && p->bounty>=30 )
         {
            sendPrivate(p,"You beated easy mission \"Bounty Hunter\" Congratulations!");
            sendPrivate(p,"*points 5000");
            set_tag(p,mission1,off);
         }

         else if (c->check("abort:easy:1"))
         {
            if (get_tag(p,mission1)==on)
            {
               sendPrivate(p,"You aborted easy mission \"Bounty Hunter\"");
               set_tag(p,mission1,off);
            }

            else if (get_tag(p,mission1)!=on)
            {
               sendPrivate(p,"You never started easy mission \"Bounty Hunter\"");
            }
         }

         // END OF EASY MISSION BOUNTY HUNTER CODE


also i got this in spawn.h
Code: Show/Hide
#define mission1 1

#define on 1  // mission is on
#define off 0 // mission is off


also to samapico:
yup ur right its in datatypes.h
Purge - Sun Apr 06, 2008 8:19 pm
Post subject:
The bot only realizes the player won when he types in the command since that is the only place you are checking for a win. So you must check for a win in a player event in spawn.cpp like Player_Prize (I think).
Samapico - Sun Apr 06, 2008 11:05 pm
Post subject:
Quick suggestion for cleaner code:
Code: Show/Hide
if (get_tag(p,mission1)!=on)
{
sendPrivate(p,"You started an easy mission \"Bounty Hunter\" Type !abort:easy:1 anytime during the game to abort this mission");
set_tag(p, mission1, on);
}
else if (get_tag(p,mission1)==on)
sendPrivate(p,"You already started easy mission \"Bounty Hunter\" Type !abort:easy:1 to abort mission.");

You defined the 'off' value, you might as well use it... and since you're doing the "else" part, you only need to get_tag once, since the tag only has 2 possible values.
Code: Show/Hide
if (get_tag(p,mission1)==off)
{
sendPrivate(p,"You started an easy mission \"Bounty Hunter\" Type !abort:easy:1 anytime during the game to abort this mission");
set_tag(p, mission1, on);
}
else
{
sendPrivate(p,"You already started easy mission \"Bounty Hunter\" Type !abort:easy:1 to abort mission.");
}


And to fix your problem, you must do as Purge said. Typically, most of your plugin code should be in spawn.cpp, in the various events. The commands.cpp should only include stuff that are directly triggered by !commands, like turn on/off something, like you're doing with your mission. However, once the command is done, you have to rely on events to know what's going on.
You can also use global variables in spawn.cpp and command.cpp if you declare them in spawn.h, in the botInfo class declaration.
hellzlaker - Mon Apr 07, 2008 3:50 pm
Post subject:
ok thanks
hellzlaker - Mon Apr 07, 2008 5:40 pm
Post subject:
Also I am going to create a tag that deals with current time, and where would exactly i would put in spawn.ccp? ( i was guessing like playermove =\)

this is just kind of how it will look like

Code: Show/Hide

#include <ctime> // header


Code: Show/Hide

if (get_tag(p,0)==1)
{
time_t breaktime=time(0);
int freezetime = (int) breaktime;
if (breaktime==freezetime+300)
{
set_tag(p,0,0);
}
}

Bak - Mon Apr 07, 2008 8:48 pm
Post subject:
EVENT_TICK happens once a second. you can set like the time to 300 when they start and every EVENT_TICK have a countdown.

Code: Show/Hide

// inside EVENT_TICK

// go through every player in the arena
for (_listnode <Player> *parse = playerlist->head; parse; parse = parse->next)
{
  Player* p = parse->item;

  int playing = get_tag(p,TAG_INDEX_PLAYING);

  if (playing == ON)
  {
    int remaining = get_tag(p,TAG_INDEX_TIME);

    if (remaining <= 0)
      // you lose
      set_tag(p,TAG_INDEX_PLAYING,OFF);
    else
      set_tag(p,TAG_INDEX_TIME, remaining - 1);
}

hellzlaker - Mon Apr 07, 2008 9:11 pm
Post subject:
what do you mean by go through every person in arena ?

and i dont get that for()
Code: Show/Hide

// go through every player in the arena
for (_listnode <Player> *parse = playerlist->head; parse; parse = parse->next)


EDIT: also can you have more then 1 EVENT_TICK?
Samapico - Mon Apr 07, 2008 11:22 pm
Post subject:
check how the get_tag function is done, it uses the same thing (except it's a while loop instead of a for loop).
Basically, "playerlist" is a linked list...

A linked list is made of "nodes"
Each node contains 3 important information:

A pointer to the previous node of the list
A pointer to the next node of the list (parse->next)
A pointer to the actual data (parse->item)

For example, in playerlist, the items are 'Player' structs.

So what that loop does, is initialize a pointer to the start of the list (playerlist->head). Once you've done what you wanted with that item, you advance to the next (parse = parse->next)
The stop condition of the loop is 'parse', which means as long as the pointer is not NULL, it will keep going. The last item of the list doesn't have any 'next' item, so at that point you will get the NULL value.
Samapico - Mon Apr 07, 2008 11:24 pm
Post subject:
As for you EVENT_TICK question... there is only one EVENT_TICK event, however, you can have more than one countdowns going at once. By default, there are 4 countdowns set. Look in spawn.h you will find the initialization of them; looks like 'int countdown[4];' or something. You can put as many countdowns as you wish. You just have to adjust the code in the EVENT_TICK part.
Bak - Tue Apr 08, 2008 12:40 am
Post subject:
why would you want more than one EVENT_TICK ?

I'd try to explain the for loop but samapico is pretty much right. It involves pointers and structures and templates, which aren't hard on their own but if you're trying to learn all of them at once it can be overwhelming. Suffice it to say there's a list of every Player* in the arena called playerlist, and that's how you go through it.
hellzlaker - Sun Apr 13, 2008 8:28 pm
Post subject:
wtf this doesnt compile right!

Code: Show/Hide
      {
         for (int i = 0; i < 4; ++i)
            --countdown[i];

         if (get_tag(p,breaktime)!=0)
         {
            int remainingtime = get_tag(p,breaktime);
            set_tag(p,breaktime,remainingtime-1);
         }






      }
and get those errors
Code: Show/Hide
1>------ Build started: Project: default, Configuration: Debug Win32 ------
1>Compiling...
1>spawn.cpp
1>c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\src\player.cpp(108) : warning C4996: 'strncpy': This function or variable may be unsafe. Consider using strncpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1>        c:\program files\microsoft visual studio 9.0\vc\include\string.h(157) : see declaration of 'strncpy'
1>c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\src\player.cpp(109) : warning C4996: 'strncpy': This function or variable may be unsafe. Consider using strncpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1>        c:\program files\microsoft visual studio 9.0\vc\include\string.h(157) : see declaration of 'strncpy'
1>c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\spawn.cpp(11) : warning C4005: 'UNASSIGNED' : macro redefinition
1>        c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\src\clientprot.h(14) : see previous definition of 'UNASSIGNED'
1>c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\spawn.cpp(59) : error C2065: 'p' : undeclared identifier
1>c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\spawn.cpp(61) : error C2065: 'p' : undeclared identifier
1>c:\documents and settings\owner\desktop\programing\c++\dc missons\dcmissions\spawn.cpp(62) : error C2065: 'p' : undeclared identifier
1>Build log was saved at "file://c:\Documents and Settings\Owner\Desktop\Programing\c++\DC missons\DCmissions\Debug\BuildLog.htm"
1>default - 3 error(s), 3 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


when i delete that code compiles just fine :\
Purge - Sun Apr 13, 2008 10:23 pm
Post subject:
You have to cycle through the playerlist so that it can search for a player to check tags.

Code: Show/Hide

_listnode <Player> *parse = playerlist->head;
while (parse)
{
      Player *p = parse->item;

      if (get_tag(p,breaktime)!=0)
            {
                  int remainingtime = get_tag(p,breaktime);
                  set_tag(p,breaktime,remainingtime-1);
             }

       parse = parse->next;
}


That code should work. Also, you may want to fix those warnings regarding deprecated strings. Try declaring #define CRT_SECURE_NO_DEPRECATE in spawn.h.
Samapico - Sun Apr 13, 2008 11:16 pm
Post subject:
yeah... there is no 'p' in the EVENT_TICK part of the code. (C2065: 'p' : undeclared identifier)
hellzlaker - Mon Apr 14, 2008 3:54 pm
Post subject:
i declared that and still got same 3 errors also where could i find how to keep track of player kills? like bounty i know is p->bounty and there is EVENT player prize.. but is there a kill event?
Samapico - Mon Apr 14, 2008 5:16 pm
Post subject:
there is a death event... where there's a death, there's a kill.


And you can't just declare 'p' in EVENT_TICK... well you can, but it will be useless, you have to do what purge said, which is cycle through ALL the players every tick.
hellzlaker - Mon Apr 14, 2008 5:50 pm
Post subject:
Code: Show/Hide
   case EVENT_PlayerDeath:
      {
         Player *p = (Player*)event.p[0],
               *k = (Player*)event.p[1];
         Uint16 bounty = (Uint16)(Uint32)event.p[2];
         Uint16 flags = (Uint16)event.p[3];
      }



kinda confusing and i assume *k is the killer, so if i would try something like keep track if a player killed 3 people without dying (like a spree) what would i do?
[/code]
Purge - Mon Apr 14, 2008 7:17 pm
Post subject:
Yes, the pointer *k is used for the killer.

To check for sprees, a simple way to do it is to check the player every time he kills. At each kill, increment an integer variable by 1, which will represent the amount of kills the player has before he dies. Whenever the player dies, reset that variable to 0.
Samapico - Mon Apr 14, 2008 8:32 pm
Post subject:
<what purge said> using tags, of course.
tcsoccerman - Mon Apr 14, 2008 9:35 pm
Post subject:
for more information, you could check out smongs spree module for ASSS (not merv). search for it in asss custom modules.
hellzlaker - Tue Apr 15, 2008 12:27 am
Post subject:
ye but how do you check every time player kills?
anything like?

Code: Show/Hide

   case EVENT_PlayerDeath:
      {
         curentspree = get_tag(spree);
         set_tag(k,spree,curentspree+1);

         Player *p = (Player*)event.p[0],
               *k = (Player*)event.p[1];
         Uint16 bounty = (Uint16)(Uint32)event.p[2];
         Uint16 flags = (Uint16)event.p[3];
      }


i don't understand it, above i gave the killer a point to the spree every time he kills, but how do i control when he dies, anyway i know the code above is wrong its just i don't understand how to access it correctly
Purge - Tue Apr 15, 2008 9:53 am
Post subject:
Every time a player kills or dies the event Player_Death gets called. So you would just write something that will keep track of the players' kills using an integer variable (like int kills).

You can use tags to keep track of the actual players that are currently spreeing (like set_tag(k, SPREE, 1)) so you can differentiate them from other players. You must also remember to check if a player on a spree dies to reset his int kills back to 0 and remove the tag (using killTags(k)).

There should be a rampage plugin out there for MERV made by 50% Packetloss that is open source, so you may learn by that.
Samapico - Tue Apr 15, 2008 11:19 am
Post subject:
hellzlaker wrote:
ye but how do you check every time player kills?
anything like?

Code: Show/Hide

   case EVENT_PlayerDeath:
      {
         curentspree = get_tag(spree);
         set_tag(k,spree,curentspree+1);

         Player *p = (Player*)event.p[0],
               *k = (Player*)event.p[1];
         Uint16 bounty = (Uint16)(Uint32)event.p[2];
         Uint16 flags = (Uint16)event.p[3];
      }


i don't understand it, above i gave the killer a point to the spree every time he kills, but how do i control when he dies, anyway i know the code above is wrong its just i don't understand how to access it correctly


You're not 'too' far of the answer...

First, you must do your stuff AFTER the *p and *k variables have been assigned, else it makes no sense:
Code: Show/Hide

case EVENT_PlayerDeath:
{
Player *p = (Player*)event.p[0];
Player *k = (Player*)event.p[1];
Uint16 bounty = (Uint16)(Uint32)event.p[2];
Uint16 flags = (Uint16)event.p[3];

//do stuff here
}

Same goes for all other events... depending on the event, the information is first grabbed from the event data, then you can use it.

Now, you incremented the killer's spree... well, almost... your get_tag was missing the player argument, and your 'currentspree' variable wasn't declared correctly (no type):

Code: Show/Hide

int curentspree = get_tag(k, spree);
set_tag(k,spree,curentspree+1);


Now, only thing you need to do to reset the killed player's bounty is add:

Code: Show/Hide

set_tag(p,spree,0);


Now... a small thing that could give you some hard-to-find bugs... what if player A lays some mines, then leaves the arena... and someone gets killed by these mines. The killer pointer 'k' will be 'NULL', and the tags will already be removed (see Player_Leave event). So you have to check if k is not NULL before attempting to do anything. And just because it is always safer to check for NULL pointers before using them, I'd do the same with 'p', even if it shouldn't ever be NULL... But when you see these error messageboxes saying stuff like 'Memory cannot be read at 0x00000000', it's because the program tried to use a NULL pointer. NULL being simply the value 0 (see #define NULL 0, somewhere in the code)

One last thing, constant values are usually used with all caps... so your variable 'spree' should be 'SPREE'; doesn't change anything in how the code works, but it's cleaner/more standard.

Final result:
Code: Show/Hide

#define SPREE 0

...

case EVENT_PlayerDeath:
{
   Player *p = (Player*)event.p[0];
   Player *k = (Player*)event.p[1];
   Uint16 bounty = (Uint16)(Uint32)event.p[2];
   Uint16 flags = (Uint16)event.p[3];

   if (k != NULL)
   {
      int currentspree = get_tag(k, SPREE);
      set_tag(k, SPREE, currentspree+1);

      //Send arena messages if you want
      if (currentspree == 5)
         sendPublic("*arena OMG " + (String)k->name + " is on a killing spree! (" + (String)currentspree + ":0)");
   }
   if (p != NULL)
   {
      //Reset dead player's spree
      set_tag(p, SPREE, 0);
   }
}


Also, you might want to reset a player's spree on the Player_Ship and Player_Team events.
hellzlaker - Fri Apr 25, 2008 6:13 pm
Post subject:
My bot DLL is coming very good but im running in some problems on the way

my question is this

in a turf zone and can you find out how many flags is the team holding (or player, same thing in turf right?)

i tried using p->flagCount but it didn't work

any one know?
Samapico - Fri Apr 25, 2008 6:58 pm
Post subject:
Similar to the playerlist, there is a 'flaglist'. You scroll through it in the same way you'd scroll through the playerlist, except the data items are not 'Player' structs, but 'Flag' structs. Each 'Flag' item holds the ID of the flag, the position of the flag, and the team that holds it. (If no one is owning the flag, I believe the 'team' is 0xFFFF, or -1, or UNASSIGNED)
hellzlaker - Wed Apr 30, 2008 8:32 pm
Post subject:
thanks Samapico ur amazing but i got few more questions

like if i do something if player types !checkFlags the bot will tell him how many flags his team owns and how many doesn't,

i did the scroll through flags

Code: Show/Hide
for (_listnode <Flag> *parse = flaglist->head; parse; parse = parse->next);


but then i kinda got confused

using the
Code: Show/Hide
struct Flag
{
   Uint16 x, y;
   Uint16 team;
   Uint16 ident;
};


i guess you access each flag with 'Flag.team' to find out which team flag belongs to but i dont get which one ? is it more like Flag.1.team ? u understand that there is ident but you would access it with Flag.ident to find flag' identity right?

i just found out that you access flag like a namespace with the '::' so its Flag::team

but my question is the same, how do you check which flag is on which team since you cant do Flag::ident1::team ?
Purge - Wed Apr 30, 2008 9:56 pm
Post subject:
You should be able to check the values within the struct using f->(Uint16). For example, to check for flags on a team, use f->team.

Notice how this is similar to checking entries in the playerlist.
Samapico - Thu May 01, 2008 1:35 am
Post subject:
if you scroll through the whole flag list, you don't have to worry about the ident, especially if you just want to count them.

just something like

Code: Show/Hide


int flagcount[2] = { 0 , 0 };
for (...)
{
  Flag* f = parse->item;
  flagcount[ f->team ]++;
}


To access the 'team' field, you have to use -> because you have a pointer.

Basically, the -> operator is a shortcut for 'field of the object pointed by'
For example,
f->team
is exactly the same as
(*f).team (The * operator before a variable name refers to the object pointed by a pointer)
hellzlaker - Thu May 01, 2008 9:57 pm
Post subject:
honestly i am confused

int flagcount[2] = { 0 , 0 };

you just declared an array which contains 2 variables and both of them are 0, :\ i dont get that at all, i mean i get that its an array but why 2 values?

Flag* f = parse->item


This part i kinda get but for some reason VC++ told me "error C2065: 'parse' : undeclared identifier"

flagcount[ f->team ]++;

this part is just as confusing as first, as i understand, it checks what team flag is on, and writes a value for flagcount[ number of the team] to increase by 1

so if flag was on freq 5, then flagcount[5] would increase by one?
Samapico - Thu May 01, 2008 11:57 pm
Post subject:
oh.. yeah I did a couple of mistakes...

I put 2 values because I supposed there were only 2 teams. And if I did that, I should have included checks to make sure that f->team is either 0 or 1. And for the 'undeclared identifier: parse', the 'for (...)' I put in there was the for loop used to scroll through the flags (see below), just felt lazy.


If you have private freqs and can have like 9999 different freqs, and if you only want to know how many flags YOU have and how many flags you don't, you could do it like this:
Code: Show/Hide

void ShowFlags(Player * p)
{
   int ownedflags=0;
   int enemyflags=0;
   for (_listnode <Flag> *parse = flaglist->head; parse; parse = parse->next)
   {
     Flag* f = parse->item;

     if (f->team == p->team)
       ownedflags++;
     else
       enemyflags++;
   }
   sendPrivate(p, "Your team owns " + (String)ownedflags + "/" + (String)(ownedflags+enemyflags) + " flags.");
}


If you call this function for a player, it will send him something like:

BOT> Your team owns 5/16 flags.



If you have a fixed number of teams, and want to know the flags of each team:
Code: Show/Hide

int flagcount[NTEAMS];
ZeroMemory(flagcount, sizeof(int)*NTEAMS); //Sets to 0 the whole array

for (_listnode <Flag> *parse = flaglist->head; parse; parse = parse->next)
{
  Flag* f = parse->item;
  if (f->team >= 0 && f->team <= NTEAMS)
    flagcount[ f->team ]++;
}

k0zy - Fri May 02, 2008 2:39 am
Post subject:
I still think
Code: Show/Hide
(String)ownedflags
is a bad idea.

It looks like you're actually casting the integer into a String. But that's not the case. (Because an int simply isn't a String. The memory structure of them has nothing in common.)
That works, because Catid wrote it's own string class and overloaded the () operator.
What happens here is, it's constructing a new String object from the integer, and after that exposing its internal char*.
So it isn't casted to a String, but to a char*.
*shudder*

My point is, all that won't work outside of MERVBot.
So you can as well do it the right way.
Convert the int into a char*, because sendPrivate expects a char* anyways.

And while you're at it, use C++ casting operators instead of the old C ones.
Purge - Fri May 02, 2008 8:00 am
Post subject:
Don't forget to add parse = parse->next right before you close the loop or else the bot will crash.
Samapico - Fri May 02, 2008 1:57 pm
Post subject:
Bob Dole.. Bob Dole... Bob Dole...... bob dole.... bob... dole.... wrote:
I still think
Code: Show/Hide
(String)ownedflags
is a bad idea.

It looks like you're actually casting the integer into a String. But that's not the case. (Because an int simply isn't a String. The memory structure of them has nothing in common.)
That works, because Catid wrote it's own string class and overloaded the () operator.
What happens here is, it's constructing a new String object from the integer, and after that exposing its internal char*.
So it isn't casted to a String, but to a char*.
*shudder*

My point is, all that won't work outside of MERVBot.
So you can as well do it the right way.
Convert the int into a char*, because sendPrivate expects a char* anyways.

And while you're at it, use C++ casting operators instead of the old C ones.
Yeah... I do it because it works tongue.gif And the first example of displaying numbers I saw was made like that, so I kept using it... But I guess it's not the best way. But it works and it's visually simple icon_wink.gif
Samapico - Fri May 02, 2008 1:58 pm
Post subject:
Purge wrote:
Don't forget to add parse = parse->next right before you close the loop or else the bot will crash.
It's in the 'for' statement
Bak - Fri May 02, 2008 2:55 pm
Post subject:
and if it wasn't the bot wouldn't crash; it would loop forever icon_smile.gif

using explicit String casting is fine for mervbot.
Purge - Fri May 02, 2008 6:19 pm
Post subject:
Ah, I overlooked the for loop... I thought everything was in a while loop. sa_tongue.gif

I believe the bot would crash considering it did when I left out the parse = parse->next when I was messing around. An infinite for loop would crash the bot, wouldn't it?
hellzlaker - Fri May 02, 2008 8:11 pm
Post subject:
Purge wrote:
Ah, I overlooked the for loop... I thought everything was in a while loop. sa_tongue.gif

I believe the bot would crash considering it did when I left out the parse = parse->next when I was messing around. An infinite for loop would crash the bot, wouldn't it?


yes any infinite loop would, since when the bot is in a loop it doesn't send packets and gets kicked

(correct me if i am wrong)


to samapico: thanks i get it now but just a quick question, wouldn't just by declaring flagCount easier like int flagcount[], instead of int flagcount[2] ?
Bak - Fri May 02, 2008 10:35 pm
Post subject:
in general you can't declare arrays without giving sizes. In this case you can since you initialize it right away the compiler can figure out it's size is 2. If you try to compile "int flagcount[];" it will complain whereas "int flagcount[2];" is fine.

the bot getting kicked is not a crash. If you want to see what a crash looks like do
Code: Show/Hide
((int*)0) = 0xbeef;
and run it.
Cheese - Thu Jun 26, 2008 2:30 am
Post subject:
as long as this is here, ive got
Code: Show/Hide

case EVENT_CreateTurret:
      {
         Player *turreter = (Player*)event.p[0];
         Player *turretee = (Player*)event.p[1];
         
         sendPublic((String)turreter + " attached to " + (String)turretee);
         
      }
      break;
case EVENT_DeleteTurret:
      {
         Player *turreter = (Player*)event.p[0];
         Player *turretee = (Player*)event.p[1];
         
         sendPublic((String)p->turreter + " detached from " + (String)p->turretee);
      }
      break;


doesnt compile, obviously, because p->turreter sucks.
neither (String)p->turreter nor (String)turreter works...
how would i get it to work?



-edit-
and since ive already posted here, an example of checking the first part of an arena message or server error, and doing something with it would be nice =) (because my way sucks and doesnt work half the time)
aka Team goal!/Enemy goal!
k0zy - Thu Jun 26, 2008 10:50 am
Post subject:
Try turreter->name or something...

Of course you can't cast a pointer to the string class Catid wrote.

Like I explained before, the casting in this thread only worked because Catid did some nasty things with his string class.
Samapico - Thu Jun 26, 2008 5:58 pm
Post subject:
Quote:
-edit-
and since ive already posted here, an example of checking the first part of an arena message or server error, and doing something with it would be nice =) (because my way sucks and doesnt work half the time)
aka Team goal!/Enemy goal!
emm... there is a 'score' event you know? tongue.gif
Cheese - Sat Jun 28, 2008 3:10 am
Post subject:
and yes, turreter->name worked very nicely, thanks...
All times are -5 GMT
View topic
Powered by phpBB 2.0 .0.11 © 2001 phpBB Group