http://www.xfire.com/video/625d3fQuote:
[18:08] php: kicking bots
[18:08] php: is zo easy
Coming soon to a libcod installation near you
Printable View
http://www.xfire.com/video/625d3fQuote:
[18:08] php: kicking bots
[18:08] php: is zo easy
Coming soon to a libcod installation near you
For people interested, use the stock function SV_DropClient then after that set the client's state to CS_FREE, that's all folks.
Would love this.
Solves a few problems I have with the old method.
GJ.
Ok, merged all stuff: https://github.com/kungfooman/libcod...2e49446ff4eac9
Download: http://killtube.org/downloads/libcod/2014_05_22/
Usage:
Credits to php for discovering this method and IzNoGod for implementing it in libcod. :)Code:[20:07] IzNoGoD:
entnum = players[i] getentitynumber();
kick(entnum);
free_slot(entnum);
Video by IzNoGod: http://www.xfire.com/videos/625d3f
Also possible without libcod?
Here's a challenge for you;
Changing bot names.
Please look up the word "challenge" in a dictionary:
Attachment 710Quote:
A test of one's abilities or resources in a demanding but stimulating undertaking
I'm only guessing here but I think he's manipulating the default bot name (Which can be done without libcod by editing cod2_mp with a hex editor, but the bot name is limited to 3 chars without libcod) which affects all bots globally.
If its possible to individually change their name (Without making your own scoreboard/obituary) then by all means prove me wrong =D
Of course im manipulating the bot names individually, however, it seems like i missed something, as the bot is in fact renamed (in rcon status), but ingame it is still botxx
http://cod1.eu/screenshots/bots_name.png
PHP Code:
names = [];
names[names.size] = "Rob";
names[names.size] = "Richard";
names[names.size] = "Jim";
names[names.size] = "IzNoGoD";
names[names.size] = "Harry";
names[names.size] = "Wizard";
names[names.size] = "Pancakes";
for(i=0;i<15;i++) {
b = addtestclient();
b renamebot(names[randomInt(names.size-1)]);
Lmao.
Looks like I was wrong. Makes me want to strap down and learn how libcod works. Well done.
Any chance of including your rename method in a future libcod update?
Found a bug with kicking the bots.
It seems that if you create a testclient & spawn them (If they're not spawned it will not trigger the bug) it will crash the server after creating & spawning over 1.3k bots.
Heres the error it will give:
Attachment 711
You can duplicate this crash with ease. On start gametype, add 64 testclients, spawn them, then cycle the map. Within 3-5 minutes you will go through 1.3k bots and it will crash the server.
It will do that for any spawned entity - there is obviously a limit to the number of such entities you can spawn.
Solution: every time you kick a bot, also remove it from all spawn arrays in _spawnlogic.gsc.
For changing bot names;
I didn't check if it only works with cl->name or userinfo so I set both and I really don't care to find out.PHP Code:
void PlayerCmd_renamebot(int a1) {
char* key = Script_GetString(0);
char userinfo[MAX_STRING_CHARS];
getuserinfo(a1, userinfo, sizeof(userinfo));
/*char* value = Info_ValueForKey(userinfo, key);
if(value == NULL)
Script_AddString("");
else
Script_AddString(value);*/
Info_SetValueForKey(userinfo, "name", key);
setuserinfo(a1, userinfo);
client_t* cl = getclient(a1);
if(cl) {
memcpy(&cl->name[0], key, 32);
cl->name[31] = '\0';
}
printf("name = %s\n", cl->name);
}
As for name changing instantly, just call *_UserinfoChanged (harder way for non-libcod people)
For convience I held on to the q3/wolf SDK name conventions so you can look it up yourself what it does and all.
Easier way is just to use the builtin script function
Usage:Quote:
UpdateClientNames()
Module: Level
MP Only
Summary:
Update all of the client names: only works in 'manual_change' mode
PHP Code:
newname = "harry you're a wizard";
players=getentarray("player","classname");
for(i=0;i<players.size;i++){
if(players[i] isbot()) {
players[i] renamebot(newname);
}
updateclientnames(); //calling it for every bot name change in a loop is not recommended except when you're only changing one bot name
//since it's a loop let's call it at the end
//it will notify in a iprintln with "bot<number> changed name to <newname>"
//so find the UserinfoChanged or set the start of that string (hex edit) to \0
}
As for the CoDExtended functions if you'd like to convert them to libcod, just look up the Q3/WOLF SDKPHP Code:
void PlayerCmd_isbot(int a1) {
client_t* cl = getclient(a1);
if(cl) {
if(cl->remoteAddress.type == NA_BOT)
Script_AddBool(true);
else
Script_AddBool(false);
} else {
Script_AddBool(false);
}
}
a1 = entityNumber
getclient = function gets client_t pointer for number
Epic, I'll definitely use your method soon and post results.
Also, fixed my other problem by moving bots to spectator before kicking.
Cheers all for the help!
Before I attempt to implement the method into my libcod, I have a quick question;
Why is it
instead ofCode:void PlayerCmd_renamebot(int a1) {
since you doCode:void PlayerCmd_renamebot(string newname) {
Code:players[i] renamebot(newname);
Because it is a method being called on a player, and the integer is the entitynumber.
The function itself gets the string you want, using getStackString() or something named quite similar.
Alright so keep in mind that libcod is new for me so I don't understand it much at all.
That being said... I have a really noob problem.
I'm getting this when compiling;
So i'm guessing those functions don't exist?Code:##### COMPILE cod2_1_0 GSC_PLAYER.CPP #####
gsc_player.cpp: In function "void PlayerCmd_renamebot(int)":
gsc_player.cpp:59:35: error: "Script_GetString" was not declared in this scope
gsc_player.cpp:60:19: error: "MAX_STRING_CHARS" was not declared in this scope
gsc_player.cpp:61:21: error: "userinfo" was not declared in this scope
gsc_player.cpp:61:47: error: "getuserinfo" was not declared in this scope
gsc_player.cpp:68:46: error: "Info_SetValueForKey" was not declared in this scope
gsc_player.cpp:69:29: error: "setuserinfo" was not declared in this scope
gsc_player.cpp:71:5: error: "client_t" was not declared in this scope
gsc_player.cpp:71:15: error: "cl" was not declared in this scope
gsc_player.cpp:71:32: error "getclient" was not declared in this scope
Edit: aha... looking through the q3 source code I see some of these methods... might be able to work this out
Edit2: Yeah.. nah. Do I really have to move over all these methods from the q3 source? Some of them require more methods (Example: "getuserinfo" requires "Q_strncpyz" which requires "strncpy" etc) which is making this a mess for me to understand/work out.
Is it possible for you to supply a precompiled version?
Lol i'm dumb I only just realized that your code was for cod1 CodExtended.
Could someone with the skills change the bot names for cod2 using libcod and share the code? Would be a very very very useful feature for me. =D
I'm getting some weird errors when kicking meatbots.
Basically, I created a monitor (code below) to add a bot if team size < 6, and remove a bot if team size > 6 && there is at least one bot in the team.
The problem is:
I join the server and a team, the bot is kicked;
The bot is still in the server, although the slot was freed (first image);
The bot still counts as being in the team I joined, so the server keeps trying to kick it constantly;
When I leave the server, this "ghost" bot rejoins the team (the server shows 11 players only, since its slot was freed);
When I reconnect, I use the slot of the kicked bot. The team score hud is duplicated (second image), and, as a spectator, I keep aiming at the other bots (which is what meatbot's check enemy function does, in an infinite loop);
At this moment, when I join the same team I joined earler, I get disconnected - it seems that I have self.isbot defined (the kicked bot had this it defined), so I count as a bot and the bot monitor tries to kick me to make room for myself, lol;
After I disconnect, the server keeps trying to kick whoever is in the slot I was using, so, in the console, it prints "Client 1 is not active" every time it goes through the monitor function.
Attachment 1309
Attachment 1308
PHP Code:
botMonitor()
{
self endon("intermission");
currentteam = "allies";
for(;;)
{
// start the monitor a while after map loading
timepassed = (getTime() - level.starttime) / 1000;
delayonstart = 20;
if
(
(timepassed > delayonstart) &&
(getCvar("mod_allow_bots") == "1")
)
{
// get bot count and player count for the current team
botsonteam = 0;
playersonteam = 0;
players = getentarray("player", "classname");
for(i = 0; i < players.size; i++)
{
if(players[i].pers["team"] == currentteam)
{
if
(
(isDefined(players[i].isbot)) ||
(players[i] getIP() == "0")
)
{
botsonteam++;
}
else
{
playersonteam++;
iprintln(players[i].name);
}
}
}
// add a bot to the current team if it is not complete
botmaxnumber = getCvarInt("mod_bots_" + currentteam);
if((playersonteam + botsonteam) < botmaxnumber)
{
reAddBot(currentteam);
}
else
{
// remove a bot from the current team if it has too many
if
(
(botsonteam > 0) &&
((playersonteam + botsonteam) > botmaxnumber)
)
{
iprintln("trying to kick a bot from " + currentteam);
level kickBotFromTeam(currentteam);
}
}
if(currentteam == "allies")
{
currentteam = "axis";
}
else
{
currentteam = "allies";
}
}
wait(0.5);
}
}
Any ideas?PHP Code:
kickBotFromTeam(team)
{
players = getentarray("player", "classname");
for(i = 0; i < players.size; i++)
{
if
(
(players[i].pers["team"] == team) &&
(
(isDefined(players[i].isbot)) ||
(players[i] getIP() == "0")
)
)
{
entnum = players[i] getentitynumber();
kick(entnum);
free_slot(entnum);
break;
}
}
}
You have to wait a little bit before freeing slot or just use libcod from my repo, has an autofreeslot for bots so you can just normally kick it. Also your isBot definiton seems wrong, just use:
PHP Code:
isBot()
{
return self getAddressType() == 0;
}
if (self isBot())
{
bla bla...
}
1 - I tried using getAddressType() but my version of libcod is a little old :) so, whenever I'm not using .isbot I'm using getIP() == 0.
.isbot works well because it is defined when the test client is added;
2 - Are you serious??? All I had to do was to add a wait before freeing the slot??? I wasted hours last night trying to figure this out, testing and testing and testing, before writing everything in details... lol
Thanks :D