WizzKidd Report post Posted November 2, 2006 (edited) 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 Edited November 2, 2006 by WizzKidd Share this post Link to post Share on other sites
Stormer Report post Posted November 2, 2006 (edited) Thank you for posting the code Edited November 2, 2006 by Stormer Share this post Link to post Share on other sites
crusadingknight Report post Posted November 2, 2006 (edited) 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. Edited November 2, 2006 by crusadingknight Share this post Link to post Share on other sites
Knuckles Report post Posted November 2, 2006 I'll help testing by getting past the bot for you Share this post Link to post Share on other sites
Quimbly Report post Posted November 2, 2006 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
WizzKidd Report post Posted November 2, 2006 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
LabRat Report post Posted November 2, 2006 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 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
WizzKidd Report post Posted November 2, 2006 (edited) 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 November 2, 2006 by WizzKidd Share this post Link to post Share on other sites
Quimbly Report post Posted November 2, 2006 does that mean that i have to manually lvl the magic and buy sigils for each bot? Share this post Link to post Share on other sites
LabRat Report post Posted November 2, 2006 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
WizzKidd Report post Posted November 2, 2006 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
Quimbly Report post Posted November 3, 2006 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 ? Share this post Link to post Share on other sites
peeper :) Report post Posted November 3, 2006 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
Learner Report post Posted November 3, 2006 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
Quimbly Report post Posted November 3, 2006 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
WizzKidd Report post Posted November 3, 2006 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
Learner Report post Posted November 3, 2006 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
Quimbly Report post Posted November 3, 2006 (edited) 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 November 3, 2006 by Quim Share this post Link to post Share on other sites
peeper :) Report post Posted November 5, 2006 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
LabRat Report post Posted November 5, 2006 #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
Quimbly Report post Posted November 6, 2006 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
peeper :) Report post Posted November 6, 2006 BotTest = 5 seconds BotStart = 30 seconds for me Share this post Link to post Share on other sites
bkc56 Report post Posted December 15, 2006 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. Share this post Link to post Share on other sites
Tuver Report post Posted December 15, 2006 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! "); 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
LabRat Report post Posted December 15, 2006 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