Jump to content
Eternal Lands Official Forums
Sign in to follow this  
WizzKidd

RedKnight v2.0 (KillBot Source Code)

Recommended Posts

Hello All,

 

There appears to be a HIGH demand for the source code to Kill Bots and such. I have GREATLY improved the RedKnight 1.0 source code which seems to be floating around as common place. This code is the same code that drives Perun, IRON's kill bot. He has never been killed, and no-one has passed him since he began running this code! Some of my enhancements include:

 

- No more items array, All items are dynamically identified by requesting the info from the server.

- Server HostName and Port and debug level are now configurable without needing to re-compile the bot.

- New text files define what items the bot should equip and with what priority.

- The bot can now be ordered via pm to guard a particular x,y coordinate on your map and returned home when told.

- Teleport to Range, Magic Immune, and true sight are now implemented.

- Priority kill status given to people who re-enter his sight or summon.

- Better alerting when running out of essences or food.

- Support for eating all types of food.

- MANY, MANY, MANY bugs fixed.

 

Anyway, the bot can be found here: http://www.el-iron.com/downloads/redknight2.zip

Happy pwning :P

Edited by WizzKidd

Share this post


Link to post
Share on other sites

Quick recommendation: I'd rip out the fortune and story code. I've been meaning to for a while, but I've never gotten around to it.

BTW, you can have commit access to the redknight project if you want it, as I hardly have the time to work with the bot on everything anymore. (Though, I still have some patches to make to it to fix a bunch of hackish parts of the code, including moving the config to proper CSV.)

Also, I'm noticing you're using the old CONFIG_LISTS interface, and the weird player/guild config detection: You know, those HAVE been rewritten in cvs for about 4 months. :P

Edited by crusadingknight

Share this post


Link to post
Share on other sites

after many hours of troubleshooting:

as long as the char has full health it works fine but if its not at full health then it starts getting:

 

ERROR -> Packet underrun, len = 0, buf_in_use = 0

 

and starts to constanly log off and on , whats the deal with that?

Share this post


Link to post
Share on other sites

Quim, I will look into that, I believe that it's because there may be an assumption that heal can be cast.

Share this post


Link to post
Share on other sites
Quim, I will look into that, I believe that it's because there may be an assumption that heal can be cast.
case GET_YOUR_SIGILS:

 

hope that helps :mace: you need to make an index of availablle sigils - and maybe add an option for restoration once you get the magic level required. Nice work :)

Share this post


Link to post
Share on other sites

Labrat,

 

I have not looked into the reason it's failing, but you are exactly right. When writing the bot, I assumed that the manager of the bot char would ensure it had the sigls to cast the necessary spells: Heal, Restore, Magic Immune, and Teleport to Range.

 

Note, the bot does not try to cast the spells if it does not have high enough magic level. But since heal requires no magic level, it could very well be trying to cast it without the sigls and thus getting a nasty message from the server and being dis-connected (though it does check to see if you have the ess needed first). It could also be trying to warn on GM that it has ran out of health ess and not being in a guild, the server may have an issue with that? Not sure.

 

So, the easy answer for you Quimb is to level the chars up a little and get the required sigls for the above spells and join the guild. Then all should work fine for you.

 

I doubt I will go back into the code at this point, you will know why in a day or so.

Edited by WizzKidd

Share this post


Link to post
Share on other sites

The bot can't cast spells it doesn't have the sigils for, so unless you want a guardbot that can't heal, you will need to buy the sigils and give it essences to heal itself.. Levelling magic is not required as heal is a level 0 spell.

Share this post


Link to post
Share on other sites

The bot can't cast spells it doesn't have the sigils for, so unless you want a guardbot that can't heal, you will need to buy the sigils and give it essences to heal itself.. Levelling magic is not required as heal is a level 0 spell.

 

However, if you want your bot to Restore.. Yes you do have to manually level them to that level. Or, get people to donate their alts and spend $5 to rename them??

Share this post


Link to post
Share on other sites

ok i got on my alt that had the sigils and he and it works perfect now, thx for clearing that up. it will be hard to lvl 3 new chars to a skill over 20(so they can join guild) on both test and main server so i guess ill be shopping for alts. at least i got 1 already. :hug: . and another question, if the char was brand new are the pumped up stats include a/d? or would i have a 3/3 a/d bot with high p/c ?

Share this post


Link to post
Share on other sites

3/3 a/d (unless already trained) with huge p/c i think (you have to buy the 500/500 p/c though remember)

Share this post


Link to post
Share on other sites

ok i got on my alt that had the sigils and he and it works perfect now, thx for clearing that up. it will be hard to lvl 3 new chars to a skill over 20(so they can join guild) on both test and main server so i guess ill be shopping for alts. at least i got 1 already. :) . and another question, if the char was brand new are the pumped up stats include a/d? or would i have a 3/3 a/d bot with high p/c ?

Any officially approved bots as part of making their name purple get their harbest raised to 20 so they can join a guild.

Share this post


Link to post
Share on other sites

thx for all the help, ive already secured a couple of alt chars with acceptable stats. now i need to know if its legal to multilog and equip the bots with the essenses and equipment they will be using. or should this be done strickly by pm interface? im assuming the code has built in trading commands.

Share this post


Link to post
Share on other sites

im assuming the code has built in trading commands.

 

Actually, you just drop a bag at the bots feet. It will pick up the items, and use the equipment list files (which the read me file explains) to equip items. Then when you want to get items from the bot, you request a bag "/quimb bag" :)

Share this post


Link to post
Share on other sites

For those of you drooling over this, I am looking to setup a guard bot service for players similar to my trade/storebot service with a web interface as well. This service is intended for those people that dont want to worry about the code, don't have a reliable connection, or can't keep a server running.

 

I'm posting this here since it is related and WizzKidd's code & changes will be part of the code that will be used.

Share this post


Link to post
Share on other sites

requarding the elmap.cfg file, i understand that the format is

 

mapname.elm xx,yy,item#

 

for item#, -1 is used to tell the bot hes home, but what if u need to step on a teleport go gain access to a diff part of the map, and then continue to its home destination?

 

ive tried several diff ways but have been unsuccessful. once he teleports he thinks hes stuck.

 

 

one bug i did find though, when the bot is on a map it doesnt recognize it tries to do a "#beam me" and comes back as "error: unknown command" i even get the same thing when i try to say in local chat. however when i get him to say the complete "#beam me up", he will beam.

so i suppose the code would need to match in order for it to work if he was ever ended up on the wrong map.

Edited by Quim

Share this post


Link to post
Share on other sites

Works perfectly to test for me BUT when i run BotStart it does the starting in 30 seconds thing counts down goes to starts in 0 seconds then starts counting down again :/

Share this post


Link to post
Share on other sites

#beam me (and various other # commands)

 

some commands don't work as expected (they give an error), just stick 0x20 on the end and it will work fine.

Share this post


Link to post
Share on other sites

Works perfectly to test for me BUT when i run BotStart it does the starting in 30 seconds thing counts down goes to starts in 0 seconds then starts counting down again :/

 

if ur hitting the corrcet one it should say starting in 5 sec. i think the redknight.exe does the 30sec thing which does nothing

Share this post


Link to post
Share on other sites

Would anyone who's doing active development on the RedKnight2 sources please post here? I'd like to compare notes about bugs fixed (very important that everyone get fixes), features added, etc.

 

If it's more than one or two, I'll start a new thread rather than an n-way PM web. :P

Share this post


Link to post
Share on other sites
Mine you I haven't got any chance to test it. I still haven't got my C++ compiler to handle it just yet but if I coded this right when an admin type "over" to the bot it should cuz the bot to use 5 summoning stone of bear.
as I said it's hasn't been tested yet.

if((!strncmp(data,"over",3))) {
log_info("%s requested me to overkill.\n",chat_name);
send_raw_text ("Overkilling on instruction from %s\0", chat_name);
}/* use summoning stones should be 5*/
for(i = 0; i < 5; i++) {
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Bear Summoning Stone", 28))) {
str[0] = USE_INVENTORY_ITEM;
str[1] = i;
send_to_server(str,2);
break;
}














/***************************************************************************
* Copyright © 2004 See the "CONTRIBUTORS.txt" file *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifdef WINDOWS
#include <windows.h>
#endif

#include <stdarg.h>

#include "includes.h"
#include "pathfinder.h"

#include "connection.h"
#include "log.h"
#include "local.h"
#include "stories.h"
#include "items.h"

char * ROOTDIR="/usr/opt/redknight"; // Anyone actually want this?
char *quote[]={"quote", NULL};

/*********************************************/
/* TODO: FIX ALL THESE UGLY GLOBAL VARIABLES */
/*********************************************/

/* Version for the -v or --version option */
int version_major=2, version_minor=0, patch_version=0;
int boottimer, login_delay=91, attack_delay=15000;
Uint32 stand_down=(Uint32)NULL, sit_timer=(Uint32)NULL;
int guardDuty=0, guardX, guardY;

char my_name[40], my_password[40], my_guild[5], boss_name[40], enemy_guild[5], insult_message[50];
int sit_direction=HEADING_S, ttrHeading = HEADING_S, debug =0;
int hail_master, hail_everyone, hail_guild, insult_enemy;
unsigned short int verbose = 0; // Verbose mode 0|1

/* The connection: host name and port number */
char hostname[60] = "game.eternal-lands.com";
int port = 2000;

/* Extern which must pass between all functions */
char fname[60] = "elbot.cfg";
char mname[60] = "elmaps.cfg";
char inname[60];
long queue_len=0;
int last_attack;

/* Not sure where else to put this... */
char name[40], guild[5];

/* Function Prototypes */
void process_text_message(const char *msg, char *chat_name, int PM);


void process_raw_text (const Uint8*data, int data_len) {
int len, i;
int len2;
int PM=0;
//char name[40];
char chat_name[40];
char *loc;
char chat_seperator[5];

strcpy(chat_seperator, ":");
if (debug >= DEBUG_HIGH) log_info ("process raw text: %s\n", data+1);

// Someone is summoning.. increase their aggro
if (strstr(data+2,"summoned a") > 0) {
struct kill_queue *kq;
char sname[30];
for (len2 = 0; len2 < 30 && data[len2+6] != ' '; len2++) sname[len2] = data[len2+6];
sname[len2] = 0;

for(i=0; i < max_actors; i++) {
if(!strncmp(actors_list[i]->actor_name,sname,len2)) {
if (actors_list[i]->aggro > 0) {
actors_list[i]->summoner++;

if (actors_list[i]->summoner < 2)
send_pm_enhanced("Summoning is not permitted here. If you do it again, I will attack immediatley!", sname);
else {
kq = actors_list[i]->k;
kq->time = SDL_GetTicks()-1; // attack imediatley
}
}
}
}

}

if ((data[1]==c_red2+127)||(data[1]==c_red3+127)||(data[1]==c_red4+127)) {
if (debug >= DEBUG_MEDIUM) log_info ("Text is red...\n");

// The message is red.. must be serious
// check to see if they are using magic against us
if (strstr(data,"cast harm on you") > 0
|| strstr(data,"points from you") > 0
|| strstr(data,"poisoned you") > 0) {

struct kill_queue *kq;
char sname[30];
for (len2 = 0; len2 < 30 && data[len2+2] != ' '; len2++) sname[len2] = data[len2+2];
sname[len2] = 0;

if (debug >= DEBUG_MEDIUM) log_info ("%s: %s\n",sname,data+2);
for(i=0; i < max_actors; i++) {
if(!strncmp(actors_list[i]->actor_name,sname,len2)) {
if (actors_list[i]->aggro > 0) {
kq = actors_list[i]->k;
kq->time = SDL_GetTicks()-1; // attack imediatley
send_raw_text("%s has drawn first blood... Time to die!",sname);
}
}
}

// Defend against Life Drain, Mana Drain, Poison, and Harm
cast_magic_immunity();

} else if (strstr(data,"entered a pking") < 1) {
if (debug >= DEBUG_MEDIUM) log_info ("Text is unknown...\n");
send_raw_text("#gm %s",data+1);
log_info(data+1);
return;
}
}

if (strncasecmp(data+2, "[PM from ", 9) == 0) {
len = strlen (boss_name);
loc = strstr(data+2, chat_seperator);

if (debug >= DEBUG_HIGH) log_info ("I got a PM!\n");

/*len2 = loc-data- 10;
strncpy (chat_name, data+10, len2);
strcpy (chat_name+len2, "\0");*/
for (len2 = 0; len2 < 16 && data[len2+10+1] != ':'; len2++) {
chat_name[len2] = data[len2+10+1];
}
chat_name[len2] = 0;

if(!strcmp(my_name, chat_name))return; // Don't talk to myself
if (debug >= DEBUG_HIGH) log_info ("I've got %s\n", chat_name);

process_text_message(data+10+len2+2+1, chat_name, 1);
}
}


//This functions figures out the text type, and responds accordingly
void process_text_message(const char *msg, char *chat_name, int PM) {
char text[2048];
char buffer[2048]; // Misc. buffer
char *data = malloc(256);
int i=0, j=0;

if(PM==1) {
// tolower' text
while(i < strlen(msg)) {
data[i] = tolower(msg[i]);
i++;
}
data[i] = '\0';
i = 0;

if(debug>=2) log_info("PM: %s\n", data);

// Help Commands:
if((!strncmp(data, "help", 4))) {
if (get_string(&admin, chat_name, strlen(chat_name)) != -1
|| get_string(&A_player, chat_name, strlen(chat_name)) != -1
|| is_friendly_guild(chat_name) != -1) {
// Dump help info
sprintf(text, "%s%s%s", "Help - Commands:\n",
"standdown -> I will not attack for 45 seconds. \n",
"$$ -> abbreviation for standdown command. \n"
"sit -> I will return to my chair. \n");
send_pm_enhanced(text, chat_name);

if(get_string(&admin, chat_name, strlen(chat_name)) != -1) {
sprintf(text, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
"inv -> list inventory and statistics. \n",
"equip -> list equipment. \n",
"bag -> drop all items in a bag. \n",
"glst -> list protected guilds. \n",
"gadd <name> -> protect the guild <name>. \n",
"gdel <name> -> unprotect the guild <name>. \n",
"padd <name> -> protect the player <name>. \n",
"pdel <name> -> unprotect the player <name>. \n",
"guard <x,y> -> begin guarding at x,y. \n",
"home -> abandon guard post and head home. \n",
"say <text> -> have me speak a message. \n",
"over ->Over KIll comings soon \n",
"col -> #gm the game colour chart \n",
"red -> #gm a red announcment \n",
"die -> logoff and restart my program. \n");
send_pm_enhanced(text, chat_name);
}
return;

} else {
send_pm("%s Come closer, I cant see you :>", chat_name);
return;
}
}

// Basic user commands
if (get_string(&admin, chat_name, strlen(chat_name)) != -1
|| get_string(&A_player, chat_name, strlen(chat_name)) != -1
|| is_friendly_guild(chat_name) != -1) {

if (!strncmp(data,"standdown",9) || !strncmp(data,"$$",1)) {
stand_down = SDL_GetTicks() + 45000;
send_pm_enhanced("OK, I am standing down for 45 seconds.", chat_name);

sprintf(text,"Standing down at the request of %s.\n", chat_name);
send_raw_text ("#gm %c%s",127+c_purple3,text);
log_info(text);
return;
}

if (!strncmp(data,"sit",3)) {
sit_timer = SDL_GetTicks() + 15000;
send_pm_enhanced("OK, I'll take a load off for a few.", chat_name);
return;
}
}

// Admin Commands:
if(get_string(&admin, chat_name, strlen(chat_name)) != -1) {
if(get_string(&admin, chat_name, strlen(chat_name)) != -1) {
if((!strncmp(data,"bag",3))) {
log_info("%s requested me to drop my bag.\n",chat_name);
drop_all_items(chat_name);
return;
}
if((!strncmp(data,"say",3)) && data[3] != '\0' && data[4] != '\0' && data[5] != '\0') {
strncpy(text, data+4, (strlen(data+3))-1);
strcpy(text+(strlen(data+3)-2), "\0");
send_raw_text(text);
return;
}
if((!strncmp(data,"over",3))) {
log_info("%s requested me to overkill.\n",chat_name);
send_raw_text ("Overkilling on instruction from %s\0", chat_name);
}/* use summoning stones should be 5*/
for(i = 0; i < 5; i++) {
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Bear Summoning Stone", 28))) {
str[0] = USE_INVENTORY_ITEM;
str[1] = i;
send_to_server(str,2);
break;
}



return;


if((!strncmp(data,"die",3))) {
if (debug >= DEBUG_HIGH) log_info("The boss wants me to quit!\n");
send_raw_text ("#gm %cTerminating on instruction from %s",141,chat_name);
send_pm ("%s Yes sir, %s\0", chat_name, chat_name);
send_raw_text ("Terminating on instruction from %s\0", chat_name);
exit_connection (EXIT_ALL);
exit (0);
return;
}
if((!strncmp(data,"inv", 3))) {
dump_inv(chat_name);
return;
}
if((!strncmp(data,"equip", 5))) {
dump_equip(chat_name);
return;
}
if((!strncmp(data,"col", 3))) {
send_raw_text ("#gm Debug line %cc_red1 %cc_red2 %cc_red3 %cc_red3 .",127+c_red1,127+c_red2,127+c_red3,127+c_red4);
send_raw_text ("#gm Debug line %cc_orange1 %cc_orange2 %cc_orange3 %cc_orange3 .",127+c_orange1,127+c_orange2,127+c_orange3,127+c_orange4);
send_raw_text ("#gm Debug line %cc_yellow1 %cc_yellow2 %cc_yellow3 %cc_yellow3 .",127+c_yellow1,127+c_yellow2,127+c_yellow3,127+c_yellow4);
send_raw_text ("#gm Debug line %cc_green1 %cc_green2 %cc_green3 %cc_green3 .",127+c_green1,127+c_green2,127+c_green3,127+c_green4);
send_raw_text ("#gm Debug line %cc_blue1 %cc_blue2 %cc_blue3 %cc_blue3 .",127+c_blue1,127+c_blue2,127+c_blue3,127+c_blue4);
send_raw_text ("#gm Debug line %cc_purple1 %cc_purple2 %cc_purple3 %cc_purple3 .",127+c_purple1,127+c_purple2,127+c_purple3,127+c_purple4);
send_raw_text ("#gm Debug line %cc_grey1 %cc_grey2 %cc_grey3 %cc_grey3 .",127+c_grey1,127+c_grey2,127+c_grey3,127+c_grey4);
return;
}

if((!strncmp(data,"red",3)) && data[4] != '\0' && data[4] != '\0' && data[4] != '\0') {
strncpy(text, data+4, (strlen(data+4))-1);
strcpy(text+(strlen(data+4)-1), "\0");
send_raw_text("#gm %cAnnouncement: %s",127+c_red2,text);
return;
}

if((!strncmp(data,"guard",5))) {
for(i = 6; data[i] != ',' && data[i] != '\0'; i++) {
text[i-6] = data[i];
}
text[i-6] = '\0';
guardX = atoi(text);

for(j = ++i; data[j] != '\0'; j++) {
text[j-i] = data[j];
}
text[j] = '\0';
guardY = atoi(text);

send_pm("%s Okay, I will begin guarding %d,%d.", chat_name, guardX, guardY);
log_info("I will begin guarding %d,%d at %s's request.\n", guardX, guardY, chat_name);
guardDuty=1;
return;
}

if((!strncmp(data,"home",4))) {
send_pm("%s Okay, I am abandoning my post at %d,%d and heading home.", chat_name, guardX, guardY);
log_info("I am abandoning my post at %d,%d by %s's request.\n", guardX, guardY, chat_name);
guardDuty=0;
return;
}

if((!strncmp(data,"padd",4))) {
for(i = 0; data[i+5] != ']'; i++) {
text[i] = data[i+5];
}
text[i] = '\0';
if(add_string(&A_player, text, strlen(text)) == 0)
{
send_pm("%s List is already full. Maybe you should remove some people?", chat_name);
return;
}
send_raw_text("#gm %c%s was Whitelisted by %s",127+c_grey2,text,chat_name);
send_pm_enhanced("You have been Whitelisted.", text);
save_list(&A_player, "players.lst");
return;
}
if((!strncmp(data,"pdel",4))) {
for(i = 0; data[i+5] != ']'; i++) {
text[i] = data[i+5];
}
text[i] = '\0';
if(remove_string(&A_player, text, strlen(text)) == -1)
{
send_pm("%s Name could not be removed. Maybe you should check your spelling?", chat_name);
return;
}
send_raw_text("#gm %c%s was UN-Whitelisted by %s",127+c_orange2,text,chat_name);
send_pm_enhanced("You have been UN-Whitelisted.", text);
save_list(&A_player, "players.lst");
return;
}
if((!strncmp(data,"plst",4))) {
send_pm("%s Players protected:", chat_name);
pm_list(&A_player, chat_name);
return;
}
if((!strncmp(data,"gadd",4))) {
for(i = 0; data[i+5] != ']'; i++) {
text[i] = data[i+5];
}
text[i] = '\0';
if(add_string(&A_guild, text, strlen(text)) == 0)
{
send_pm("%s List is already full. Maybe you should remove some people?", chat_name);
return;
}
send_raw_text("#gm %cGuild %s was Whitelisted by %s",127+c_grey1,text,chat_name);
save_list(&A_guild, "guilds.lst");
return;
}
if((!strncmp(data,"gdel",4))) {
for(i = 0; data[i+5] != ']'; i++) {
text[i] = data[i+5];
}
text[i] = '\0';
if(remove_string(&A_guild, text, strlen(text)) == -1)
{
send_pm("%s Name could not be removed. Maybe you should check your spelling?", chat_name);
return;
}
send_raw_text("#gm %cGuild %s was UN-Whitelisted by %s",127+c_grey1,text,chat_name);
save_list(&A_guild, "guilds.lst");
return;
}
if((!strncmp(data,"glst",4))) {
send_pm("%s Guilds protected:", chat_name);
pm_list(&A_guild, chat_name);
return;
}
}
}

// Don't understand:
switch (rand_range (1, 5)) {
case 1:
send_pm("%s %s", chat_name, "Im sorry, I didn't quite hear you. Let me turn to you my deaf ear.");
break;
case 2:
send_pm("%s %s", chat_name, "You are too far away, come closer... *wink*");
break;
case 3:
send_pm("%s %s", chat_name, "Yeah, like i'm gona let ya do that! :P");
break;
case 4:
send_pm("%s %s", chat_name, "Voices, Voices... All these voices in my head :S");
break;
case 5:
send_pm("%s %s", chat_name, "I'm rubber, you're glue.");
break;


default:
/* shouldn't happen... */
//log_error ("Please update the maximum number in do_planned_restart ()");
send_raw_text ("#gm %c[Info] Not enough sarcastic messages for folks inving me. get Wizz to make more. ",127+c_purple1);
}
} else {
// Local Chat - TODO
data++; // Skip color
}
free(data);
}

// STATS STUFF
Sint16 food = 45; // Default, so we don't worry
att16 human;
att16 magic;
att16 carry;
att16 matter;
att16 ethereal;

void proc_stats(Sint16 *stat)
{
// Levels we need to know :
human.c = stat[12];
human.b = stat[13];
magic.c = stat[36];
magic.b = stat[37];
carry.c = stat[40];
carry.b = stat[41];
matter.c = stat[42];
matter.b = stat[43];
ethereal.c = stat[44];
ethereal.b = stat[45];
food = stat[46];
}

void proc_stat(Uint8 stat, Sint32 value)
{
switch(stat)
{
case HUMAN_CUR:
human.c = value;
break;
case HUMAN_BASE:
human.b = value;
break;
case MAG_S_CUR:
magic.c = value;
break;
case MAG_S_BASE:
magic.b = value;
break;
case CARRY_WGHT_CUR:
carry.c = value;
break;
case CARRY_WGHT_BASE:
carry.b = value;
break;
case MAT_POINT_CUR:
matter.c = value;
break;
case MAT_POINT_BASE:
matter.b = value;
break;
case ETH_POINT_CUR:
ethereal.c = value;
break;
case ETH_POINT_BASE:
ethereal.b = value;
break;
case FOOD_LEV:
food = value;
break;
}
}

void orderAssailants(Uint32 time) {
static Uint32 pause_timer = (Uint32)NULL;
static int last_actor_count = 0;
int i = 0, distance=0, escapee=0, offset=8;
struct kill_queue *kq;

actor *me = pf_get_our_actor();
if (me == NULL) return;

// only prioritize every 2 seconds or when we have new actors to consider!
if (pause_timer >= time && last_actor_count < max_actors) return;
pause_timer = time + 2000;
last_actor_count = max_actors;

// Prioritize
for(i=0;i<max_actors;i++) {
if(actors_list[i]) {
if(actors_list[i]->k != NULL) {
kq = actors_list[i]->k;

if (kq != first_node) {
int d = findDistance(me->x_tile_pos,me->y_tile_pos,kq->k->x_tile_pos,kq->k->y_tile_pos);

if ((d > distance || (first_node->k->heading >= HEADING_SE && first_node->k->heading <= HEADING_SW)) && first_node->k->aggro >1) {
distance = d;

struct kill_queue *tmp;
tmp = malloc(sizeof(struct kill_queue));
tmp->next = first_node->next;

first_node->next = kq->next;
first_node->prev = kq->prev;

if (kq->prev != NULL) kq->prev->next = first_node;
if (kq->next !=NULL) kq->next->prev = first_node;
else last_node = first_node;

first_node = kq;
first_node->next = tmp->next;
first_node->prev = NULL;
}
}
}
}
}
return;
}

int findDistance(meX,meY,youX,youY) {
int dx = (meX - youX);
int dy = (meY - youY);

return sqrt(dx * dx + dy * dy);
}

int teleToRange(x,y,time) {
static Uint32 pause_timer = (Uint32)NULL;
static Uint32 bc_timer = (Uint32)NULL;
Uint8 str[10];
int mEss=0, eEss=0, sEss=0, i;

// only every 5 seconds or when we have new actors to consider!
if (pause_timer >= time) return -1;
pause_timer = time + 5000;

if (ethereal.c >= 40 && magic.b >= 15) {
// Check for the ess
for(i = 0; i < 36; i++) {
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Matter Essence", 14))) mEss = inv[i].quantity;
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Energy Essence", 14))) eEss = inv[i].quantity;
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Spirit Essence", 14))) sEss = inv[i].quantity;
}
if (mEss < 20 || eEss < 20 || sEss < 20) {
if (mEss == 0 || eEss == 0 || sEss == 0) {
if (bc_timer <= time) {
send_raw_text("#gm %cI am OUT of tele to range essence. Please bring some quick!",127+c_red3);
send_raw_text("#gm %cMatter: %d Energy: %d Spirit: %d",127+c_red3,mEss,eEss,sEss);
bc_timer = time + 60000;
}
return -1;
} else {
if (bc_timer <= time) {
send_raw_text("#gm %cI am running out of tele to range essence. Please bring some quick!",127+c_red2);
send_raw_text("#gm %cMatter: %d Energy: %d Spirit: %d",127+c_red2,mEss,eEss,sEss);
bc_timer = time + 60000;
}
}
}

pf_destroy_path();

// Cast tele to range
str[0]=CAST_SPELL;
str[1]=4;
str[2]=7; // move
str[3]=0; // change
str[4]=8; // local
str[5]=2; // space
str[6]=0;
send_to_server(str, 7);

// wait and send coords.
SDL_Delay(150);
str[0]=MOVE_TO;
*((short *) (str+1)) = (Uint16) x;
*((short *) (str+3)) = (Uint16) y-1;
str[5]=0;
send_to_server(str, 6);

if (debug >= DEBUG_MEDIUM) log_info ("Attempted to Teleport.\n");
return 0;

} else if (ethereal.c < 50 && magic.b >= 15) {
send_raw_text("#gm %cI dont have enough mana to cast tele to range! Please bring SR Pots quickly!",127+c_red3);
}

return -1;
}


struct TIMER *heartbeatptr, *guildmapptr, *pf_moveptr, *selfptr, *noteptr;

// Main Timer wrappers
Uint32 last_heart_beat;
Uint8 heartbeat = HEART_BEAT;

int heartbeat_timer(Uint32 time)
{
send_to_server (&heartbeat, 1);
last_heart_beat = time;

// remove warned people from the list
remove_by_time(&PK_player,time,180);
return 1;
}

int story_timer(Uint32 time)
{
if(story == -1 || story_time > time) return 1;
read_story();
return 1;
}

// Runs every second
int notification_timer(Uint32 time)
{
static Uint8 invFull=0;

// Check to see if we are in stand down mode. Alert if so.
if (stand_down != NULL && bot_map.map[bot_map.cur_map].id == CONFIG_NULL) {
int secs = (stand_down - time) /1000;

if (stand_down <= time+1) {
stand_down = (Uint32)NULL;
send_raw_text ("Warning: stand down mode has ended!",127+c_red3);
} else if ((secs % 10 == 0 || secs == 5) && secs > 0) {
send_raw_text ("%d seconds till guard duty resumes.",secs);
}
}

if (sit_timer != NULL) {
if (sit_timer <= time+1) sit_timer = (Uint32)NULL;
}

if ((count_free_slots()== 0 || (carry.b - carry.c)==0)) {
if (invFull==0) send_raw_text("#gm %cMy Inventory is full. Someone please empty me!",127+c_purple3);
invFull=1;
} else
invFull=0;
}

int guildmap_timer(Uint32 time)
{
Uint8 str[10];
static Uint8 sitting=0;
actor *me = NULL;
int i, turns=0, fpath = 0;

if (max_actors==0) return;
if(insult_enemy == 1 && bot_map.map[bot_map.cur_map].id == CONFIG_NULL)
{
if((me = pf_get_our_actor()) == NULL || me->fighting == 1)
{
log_info("Cannot move, currently missing or fighting\n");
return 1; // Can't do anything without it
}

//orderAssailants(time);
if(first_node != NULL && stand_down == NULL)
{
if((first_node->time - (attack_delay/2)) <= time && !(first_node->k->fighting)) {
int ttr = -1;
sitting=0;

// Teleport when necessary
if (ttrHeading != 0 && first_node->time <= time) {
int ttrH1 = ttrHeading -1; if (ttrH1 < 1) ttrH1 = 8;
int ttrH2 = ttrHeading +1; if (ttrH2 > 8) ttrH2 = 1;

if (first_node->k->x_tile_pos < me->x_tile_pos-6 || first_node->k->y_tile_pos < me->y_tile_pos-6
&& (first_node->k->heading==ttrHeading || first_node->k->heading==ttrH1 || first_node->k->heading==ttrH2))
ttr = teleToRange(first_node->k->x_tile_pos, first_node->k->y_tile_pos, time);
}

// If we did not teleport then walk
//if (ttr < 0) fpath = pseudo_pf_find_path(first_node->k->x_tile_pos, first_node->k->y_tile_pos);
fpath = pseudo_pf_find_path(first_node->k->x_tile_pos, first_node->k->y_tile_pos);

// attack only when in range
int d = findDistance(me->x_tile_pos,me->y_tile_pos,first_node->k->x_tile_pos, first_node->k->y_tile_pos);
if(first_node->time <= time && d <= 7) attack(first_node->k->actor_id);
}
} else {
if(sit_timer == NULL) {
// Are we near a bag ?
for(i = 0; i < no_bags; i++) {
if(PF_DIFF(me->x_tile_pos, bags_list[i].x) < 20 && PF_DIFF(me->y_tile_pos, bags_list[i].y) < 20) {
if (bags_list[i].collected == 0) {
open_bag(i);
sitting=0;
return 1;
}
}
}
}

// Walk back to home position
int homeX = bot_map.map[bot_map.cur_map].x, homeY = bot_map.map[bot_map.cur_map].y;
if (guardDuty==1) {
homeX = guardX;
homeY = guardY;
}

if((PF_DIFF(me->x_tile_pos, homeX) > 0 || PF_DIFF(me->y_tile_pos, homeY) > 0) && pf_follow_path == 0) {
sitting=0;
if(pseudo_pf_find_path(homeX, homeY) == 0) log_error("Cannot find valid path!\n");

} else if((PF_DIFF(me->x_tile_pos, homeX) == 0 && PF_DIFF(me->y_tile_pos, homeY) == 0) && sitting != 1 && guardDuty==0) {
if (me->heading==sit_direction) {
turns=0;
if (debug >= DEBUG_MEDIUM) log_info ("Sitting: heading=%d turns=%d\n",me->heading,turns);
} else if (me->heading > sit_direction) {
str[0] = TURN_RIGHT;
turns = me->heading - sit_direction;
if (debug >= DEBUG_MEDIUM) log_info ("Sitting: heading=%d turns=%d to the left\n",me->heading,turns);
} else {
str[0] = TURN_LEFT;
turns = sit_direction - me->heading;
if (debug >= DEBUG_MEDIUM) log_info ("Sitting: heading=%d turns=%d to the right\n",me->heading,turns);
}

if (turns>0) for (i=0; i < turns; i++) { send_to_server(str,1); SDL_Delay(1400); }

str[0] = SIT_DOWN;
str[1] = 1;
send_to_server(str,2); SDL_Delay(1300);
me->heading = sit_direction;
sitting=1;
}
}
}
return 1;
}

int self_timer(Uint32 time)
{
static notifyHealth=1;
int i;
Uint8 str[10];

if (max_actors==0) return;

// Check the food level
if(food < 2)
{
for(i = 0; i < 36; i++) {
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Fruits", 6) || !strncmp(inv[i].name, "Vegetables", 10)
|| !strncmp(inv[i].name, "Cooked Meat", 11) || !strncmp(inv[i].name, "Bread", 5)
|| !strncmp(inv[i].name, "Potion of Feasting", 18)))
{
str[0] = USE_INVENTORY_ITEM;
str[1] = i;
send_to_server(str,2);
break;
}
}
}

// Drink SR pot if need be and we have one
if (ethereal.c < ethereal.b-30) {
for(i = 0; i < 36; i++) {
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Potion of Spirit Restoration", 28))) {
str[0] = USE_INVENTORY_ITEM;
str[1] = i;
send_to_server(str,2);
break;
}
}
}

// Cast restore / heal - note this will be better supported later
// when we'll check for essences, sigils, etc.
if (magic.b > 20) {
// Check Health - Cast Restore
if (matter.c < (matter.b/3)) {
for(i = 0; i < 36; i++) {
if(!strncmp(inv[i].name, "Health Essence", 14)) {
if(inv[i].quantity < 20)
send_raw_text("#gm %cI am running low on health ess. Please bring some soon!", 127+c_red1);
else if (inv[i].quantity < 9)
send_raw_text("#gm %cI am almost out of health ess. Please bring some quick!", 127+c_red2);
else if (inv[i].quantity == 0)
send_raw_text("#gm %cI am OUT of health ess and can not restore! Please bring some NOW!!", 127+c_red3);
}
}

if (ethereal.c >= 25) {
str[0]=CAST_SPELL;
str[1]=2;
str[2]=1;
str[3]=24;
str[4]=0;

send_raw_text("#gm %cI am below %d MP, so I am casting Restoration.", 127+c_red2,(matter.b/3));
send_to_server(str, 5);
} else if (notifyHealth==1) {
send_raw_text("#gm %cI am below %d MP, and dont have enough etheral points to cast Restoration!!!", 127+c_red3,(matter.b/3));
notifyHealth=0;
}
} else
notifyHealth = 1;

} else {
// Check Health - Cast Heal
if (matter.c < (matter.b -5)) {
for(i = 0; i < 36; i++) {
if(!strncmp(inv[i].name, "Health Essence", 14)) {
if(inv[i].quantity < 40)
send_raw_text("#gm %cI am running low on health ess. Please bring some soon!", 127+c_red1);
else if (inv[i].quantity < 20)
send_raw_text("#gm %cI am almost out of health ess. Please bring some quick!", 127+c_red2);
else if (inv[i].quantity == 0)
send_raw_text("#gm %cI am OUT of health ess and can not restore! Please bring some NOW!!", 127+c_red3);
}
}

if (ethereal.c >= 5) {
str[0]=CAST_SPELL;
str[1]=2;
str[2]=3;
str[3]=23;
str[4]=0;
send_to_server(str, 5);

} else if (notifyHealth==1) {
send_raw_text("#gm %cI am below %d MP, and dont have enough etheral points to cast Heal!!!", 127+c_red3,(matter.b -5));
notifyHealth=0;
}
} else
notifyHealth = 1;
}

return 1;
}

void cast_magic_immunity () {
Uint8 str[10];
int mEss=0, eEss=0, i;

if (ethereal.c >= 55 && magic.b >= 30) {
// Check for the ess
for(i = 0; i < 36; i++) {
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Magic Essence", 13))) mEss = inv[i].quantity;
if(inv[i].quantity > 0 && (!strncmp(inv[i].name, "Energy Essence", 14))) eEss = inv[i].quantity;
}
if (mEss < 20 || eEss < 10) {
if (mEss == 0 || eEss == 0) {
send_raw_text("#gm %cI am OUT of magic/energy essence. Please bring some quick!",127+c_red3);
return;
} else
send_raw_text("#gm %cI am running out of magic/energy essence. Please bring some quick!",127+c_red2);
}

// Cast Magic Immunity
str[0]=CAST_SPELL;
str[1]=4; // lenght
str[2]=19; //sigl 1
str[3]=3; //sigl 2
str[4]=17; //sigl 3
str[5]=21; //sigl 4
send_to_server(str, 6);

} else if (ethereal.c < 55 && magic.b >= 30) {
send_raw_text("#gm %cI dont have enough mana to cast magic immunity! Please bring SR Pots quickly!",127+c_red3);
}
return;
}

void do_event_loop () {
Uint32 time;

while (1) {
get_server_message();

// Normal Timers
time = SDL_GetTicks();
timer_loop(time);

SDL_Delay (50); // was 100
}
}

int read_info (char *fname) {
int intern_debug = DEBUG_NONE;

FILE *fp = fopen (fname, "r");

if(!fp)
{
char error_to_log[200];
log_info("%s %s\n", "No such file:", fname);
return 0;
}

// TODO: RE-WRITE THIS TO USE A FUNCTION IN CONFIG.C
// INIT_GLOBALS( .. ) ISN'T WHAT WE'RE LOOKING FOR
int k;
k = init_globals(fp, "hostname login password guild admin hail_master hail_everyone hail_guild insult_enemy enemy_guild insult_message sit_direction, ttrHeading", "sssssiiiissii", hostname, my_name, my_password, my_guild, boss_name, &hail_master, &hail_everyone, &hail_guild, &insult_enemy, enemy_guild, insult_message, &sit_direction, &ttrHeading);

log_info("running in debug level: %d\n", debug);

if (debug >= DEBUG_HIGH) {
log_info("geting data. errorlevel: %d\n", k);
log_info("My name is \"%s\"\n", my_name);
log_info("My password is \"%s\"\n", my_password);
log_info("My guild is \"%s\"\n", my_guild);
log_info("My boss is \"%s\"\n", boss_name);

if (hail_master == 1) {
log_info("I will hail %s as Master\n", boss_name);
}
else {
log_info("I will not hail %s as Master\n", boss_name);
}

if (hail_guild == 1) {
log_info("I will hail guild members.\n");
}
else {
log_info("I will not hail guild members.\n");
}
log_info ("My enemy guild is %s.\n", enemy_guild);

if (insult_enemy == 1) {
log_info("I will insult members of my enemy guild by saying \"%s\".\n", insult_message);
}
else {
log_info("I will not insult members of my enemy guild.\n");
}
}
return 1;
}


int init_bot()
{
#ifdef LINUX
chdir(ROOTDIR);
#endif
int err, i;

// Init
for(i=0;i<max_actors;i++)
actors_list[i]=NULL;

if (!read_info (fname)) {
log_error ("Unable to read input file %s\n", fname);
exit (57);
}
// Load Configuration Lists
load_list(&admin, "admin.lst");
load_list(&A_player, "players.lst");
load_list(&A_guild, "guilds.lst");
load_list(&PK_player, "pk_players.lst");
init_equipment_lists();

// Load the map configuration
load_map_config(mname);
// Create the timers
heartbeatptr = add_timer(20000, heartbeat_timer);
noteptr = add_timer(1000, notification_timer);

guildmapptr = add_timer(500, guildmap_timer);
pf_moveptr = add_timer(2000, timed_pf_move);
selfptr = add_timer(2100, self_timer);

err = init_connection (hostname, port);
if (err) {
exit_connection (err);
exit (2);
}

if (!login (my_name, my_password)) {
log_error ("Unable to log in as %s\n", my_name);
exit (35);
}

send_raw_text ("#gm %cOnline.",127+c_purple3);
log_info("Online\n");
do_event_loop();

exit_connection (EXIT_ALL);
log_error ("Unable to log in as %s\n", my_name);

return 0;
}


void getargs(int argc, const char ** argv)
{
for(*argv++; *argv != 0; *argv++) {
if(*argv[0] == '-')
{
if(!strcmp(*argv, "-i")) // Set config file
{
strcpy(fname, *(++argv));
continue;
}
if(!strcmp(*argv, "-m")) // Set mapfile
{
strcpy(mname, *(++argv));
continue;
}
if(!strcmp(*argv, "-d")) // Debug
{
debug = atoi(*(++argv));
if(debug > 3) debug = 3;
if(debug < 0) debug = 0;
continue;
}
if(!strcmp(*argv, "-v")) // Verbose
{
verbose = 1;
continue;
}
if(!strcmp(*argv, "-t")) // Login Timer
{
login_delay = atoi(*(++argv));
continue;
}
if(!strcmp(*argv, "-p")) // Login Timer
{
port = atoi(*(++argv));
continue;
}
if(!strcmp(*argv, "-V") || !strcmp(*argv, "--version")) // Print Version Info
{
printf("Version: ELbot %d.%d-%d\n", version_major, version_minor, patch_version);
exit(0);
}
if(!strcmp(*argv, "-h") || !strcmp(*argv, "--help")) // Print Help Info
{
printf("Usage: ELbot [arguments]\n\n");
printf(" -p [server port]\tSet the server port\n");
printf(" -d \t\t\tSet the debug level to the next argument.\n\t\t\t Possibilities are: 0 (None), 1, 2, 3(High).\n");
printf(" -i [filename]\t\tSet the input file to [filename]\n");
printf(" -m [filename]\t\tSet the map file to [filename]\n");
printf(" -h --help\t\tDisplay this information\n");
printf(" -V --version\t\tDisplay version information\n");
printf(" -v \t\t\tDisplay the info to log whenever log_data()\n\t\t\t and/or log_error() are called.\n");
printf(" -t [seconds]\t\tSet the login timer delay\n");
exit (0);
}
}
else
{
printf("Unknown argument: %s\nUse redknight --help for more details", *argv); // This shouldn't happen
exit(0);
}
}
return;
}


#ifdef WINDOWS
int Main (int argc, const char ** argv) {
#else
int main (int argc, const char ** argv) {
#endif
getargs(argc, argv);

if (login_delay > 0) {
if (login_delay < 10) printf ("\nStarting in %d seconds",login_delay);

for (boottimer=login_delay;boottimer--;boottimer>0){
if ((boottimer % 10) == 0)
printf ("\nStarting in %d seconds",boottimer);
else
printf(".");
SDL_Delay (1000);
}
}
if(!init_bot()) return 0;
}

#ifdef WINDOWS
int APIENTRY WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
return Main(_argc, (const char **)_argv);
}
#endif

Share this post


Link to post
Share on other sites

Summoning stones now have cooldown, you'd have to fork() with a 2 second delay between each stone to have that work.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×