PDA

View Full Version : Changing map on MeatBot (CoD 2)



guiismiti
12th December 2013, 01:15
Hello,

Context:

First of all, I know meatbot is not meant to be played in public / dedicated servers, and the testclients were only meant for tests.
Although, it is extremely hard to get a CoD2 server populated nowadays (less than 100 players peak playing simultaneously in brazilian servers).
The last thing I can try to do for my server is add some bots, at least temporarely, to atract players who may like the custom maps I'll use and start playing there frequently, so it will be one of the ~3 frequently populated brazilian servers.
The reasons I simply don't play in other servers - every single admin is stupid (you can't kill 10 players in a row without being called a cheater and getting kicked, and most of them don't know how to detect wallhackers), high ping from foreign servers, no servers have custom maps (at least the ones I want to play), and no servers use my mod (I'll be posting about it in a couple of weeks).


My problem:
The game stops after finishing a map. Map won't rotate, it just keeps showing the score table. Meatbot does not effectively remove the bots it creates - it moves them to spectators, and they just stay there.


So far, I have successfully editted the meatbot mod and merged with my mod, which has a lot of tools I developed or got from other mods. I tried using meatbot only (without my mod), and the same problem happens, which means it's not coming from my mod.

Anyway:
- The endmap funcion of the tdm.gsc from meatbot calls another endmap function, which is at _mbot.gsc and does not remove the bots;
- The script command for adding bots is addtestclient(), but I don't know if there's a command for deleting it;
- There is a removebot function in _mbot.gsc, and I coulnd't find any scripts calling it, and I'm not sure if it works.

Here is the removeBot funcion:



removeBot(team)
{
players = getentarray("player", "classname");


switch(team)
{
case "allies":
for(i = 0; i < players.size; i++)
{
if (!isDefined(players[i].isbot))
continue;
if(players[i].pers["team"] == "allies")
{
//players[i] notify("killed_player"); // Cepe7a
//level.bots_al--;
players[i] thread botJoin("spectator", "");
break;
}
}
break;

case "axis":
for(i = 0; i < players.size; i++)
{
if (!isDefined(players[i].isbot))
continue;
if(players[i].pers["team"] == "axis")
{
//players[i] notify("killed_player"); // Cepe7a
//level.bots_ax--;
players[i] thread botJoin("spectator", "");
break;
}
}
break;

case "all":
for(i = 0; i < players.size; i++)
{
if (!isDefined(players[i].isbot))
continue;
players[i] notify("killed_player"); // Cepe7a
players[i] thread botJoin("spectator", "");
}

//level.bots_al = 0;
//level.bots_ax = 0;
break;

default:
for(i = 0; i < players.size; i++)
{
if(players[i].name == team)
{
if(!isdefined(players[i].isbot))
{
println(players[i].name + " is not a bot");
continue;
}

/*
if(players[i].pers["team"] == "allies")
level.bots_al--;
else if(players[i].pers["team"] == "axis")
level.bots_ax--;
*/

players[i] notify("killed_player"); // Cepe7a
players[i] thread botJoin("spectator", "");
break;
}
}
break;
}
}



_mbot.gsc and tdm.gsc are attached.

Has anybody got any clues?

Tally
12th December 2013, 05:13
You can kick a bot from a server at the end of the game, but they remain in stasis - that is, they are still occupying their player slot and you can still see them if you look at the scoreboard - they show as "dead" players. This is an engine thing. There is no way to get around it. People have tried and failed to make a work-a-round for the problem, including myself.

As for meatbot rotating a server at the end of the map, this can be done if you know your way around COD script and you edit the meatbot files, but it still wont get around the problem of bots remaining in stasis, so you will eventually run out of player slots. Bots from the first map will still be occupying their player slots by the time you get to your 10th map, and by that time you would have run out of player slots.

kung foo man
12th December 2013, 10:05
There is no way to get around it. People have tried and failed to make a work-a-round for the problem, including myself.

Way with BigBrotherBot, in short:
- write in endMap() "QUIT" to log-file
- let BigBrotherBot read it, B3 sets the cvar "b3_quit" to 1, to prepare clients for reconnect, then executes "quit" on server
- server restarts automatically in an endless loop

I guess Selbie was the first one with his ZomBots-mod in 1.2? Don't know for sure.

Technical details:

1) Add in b3/parsers/cod2.py



# BigBrotherBot(B3) (www.bigbrotherbot.net)
# Copyright (C) 2005 Michael "ThorN" Thornton
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

# CHANGELOG
# 31/01/2010 - 1.2.2 - xlr8or - Removed commandsdict, inherit from codparser
# 18/04/2010 - 1.2.3 - xlr8or - Forcing g_logsync to make server write unbuffered gamelogs
# 30/05/2010 - 1.2.4 - xlr8or - Setting exception for 31 char PBid in shortversion v1.2
# 17/10/2010 - 1.2.5 - xlr8or - Don't let version exceptions be inherited by later parsers
# 14/06/2011 - 1.3.0 - courgette - remove cvar specifics as the cvar regexp and code is
# now working good on the q3a AbstractParser


__author__ = 'ThorN, ttlogic, xlr8or'
__version__ = '1.3.0'

import b3.parsers.cod
import re

import time

class Cod2Parser(b3.parsers.cod.CodParser):
gameName = 'cod2'
IpsOnly = False
_logSync = 1 # Value for unbuffered game logging


# set exceptions for this specific version of cod2
def setVersionExceptions(self):
# this shouldn't be inherited by later parsers, so restrict to this game only
if self.gameName == 'cod2':
if self.game.shortversion == '1.0' and not self.IpsOnly:
self.warning('CoD2 version 1.0 has known limitations on Authentication! B3 will not work properly!')
if self.game.shortversion == '1.2':
# cod2 v1.2 has a bug so PBid's are 31 characters long, instead of 32, override the regexp for testing PBid's
self.debug('Overriding pbid length for cod2 v1.2 with PB!')
self._pbRegExp = re.compile(r'^[0-9a-f]{30,32}$', re.IGNORECASE) # RegExp to match a PunkBuster ID
else:
pass
else:
pass


def getLineParts(self, line):


line = re.sub(self._lineClear, '', line, 1)

parts = line.split(";");
if parts[0] == "QUIT":
self.setCvar("b3_quit", "1") # prepare clients for reconnect
time.sleep(2)
self.write("quit") # now kill server (will restart in endlessloop)

for f in self._lineFormats:
m = re.match(f, line)
if m:
#self.debug('line matched %s' % f.pattern)
break

if m:
client = None
target = None
return (m, m.group('action').lower(), m.group('data').strip(), client, target)
elif '------' not in line:
self.verbose('line did not match format: %s' % line)


2) Since the server is just shutting down, the normal players need to reconnect, thats done with this:



// needs .iwd from here: http://killtube.org/showthread.php?1261-player-execClientCommand%28-quot-say-boobs-quot-%29&highlight=execclientcommand
execClientCommand(cmd)
{
player = self;
player setClientCvar("clientcmd", cmd);
player openMenu("clientcmd");
player closeMenu("clientcmd");
}
quitPlayerReconnect()
{
players = getEntArray("player", "classname");
for (i=0; i<players.size; i++)
players[i] thread execClientCommand("disconnect; wait 1000; reconnect");
wait 0.50; // make sure the commands arrive
//setcvar("sv_maprotationcurrent", "gametype tdm map mp_carentan");
logPrint("QUIT;\n");

wait 10000; // wait for death!
}
watchForQuit()
{
setcvar("b3_quit", "0");
while (1)
{
wait 0.05;
if (getcvar("b3_quit") != "1")
continue;
setcvar("b3_quit", "0");
iprintlnbold("RESTART SERVER!");
quitPlayerReconnect();
}
}

>>> in tdm.gsc::main

precacheMenu("clientcmd");
thread watchForQuit();

>>> in tdm.gsc::endMap

//exitLevel(false);
quitPlayerReconnect();


Second way) Using libcod

We just use B3 to quit the server, so we can replace that with libcod to exec "quit" when we need it.



execClientCommand(cmd)
{
player = self;
player setClientCvar("clientcmd", cmd);
player openMenu("clientcmd");
player closeMenu("clientcmd");
}
quitPlayerReconnect()
{
players = getEntArray("player", "classname");
for (i=0; i<players.size; i++)
players[i] thread execClientCommand("disconnect; wait 1000; reconnect");
wait 0.50; // make sure the commands arrive
//setcvar("sv_maprotationcurrent", "gametype tdm map mp_carentan");
closer(1204, "quit");
}

IzNoGoD
12th December 2013, 11:47
almost correct


closer(1204, "quit");
does not start the serv again....
so use this instead:


closer(1204, "quit; map mp_toujane");

kung foo man
12th December 2013, 11:56
After "quit" the process is ending and can't execute commands anymore, the restarting takes place in the startscript like server.sh:



while [ true ]
do
./cod2_lnxded +set fs_game ...
done

IzNoGoD
12th December 2013, 12:00
Whoops, meant:


closer(1204, "killserver; map mp_toujane");

as /killserver seems to properly dispose of the bots too.

Tally
12th December 2013, 12:47
Come on! Are you people going to insist that every time I say "it can't be done", you are going to make me write it out in full: "it can't be done ON A STOCK SERVER WITH NO THIRD PARTY PROGRAMS"? Well, I refuse. Rather, I am going to insist that when I say "it can't be done", that you understand that I mean on a stock server with no third party programs.

kung foo man
12th December 2013, 12:49
Yeaaaaaa10! :F

guiismiti
12th December 2013, 12:58
Come on! Are you people going to insist that every time I say "it can't be done", you are going to make me write it out in full: "it can't be done ON A STOCK SERVER WITH NO THIRD PARTY PROGRAMS"? Well, I refuse. Rather, I am going to insist that when I say "it can't be done", that you understand that I mean on a stock server with no third party programs.

The idea to restart the server is quite interesting tho.
I will certainly try it, setting tdm score limit will be set to 1000 and time limit to 0, so won't need to kick everybody all the time.

guiismiti
12th December 2013, 13:06
Whoops, meant:


closer(1204, "killserver; map mp_toujane");

as /killserver seems to properly dispose of the bots too.

Well instead of map mp_toujane I can use the code used in some mods I saw to inform the next map, to have the map rotation working effectively. I'll look for it today.

But let me check if I understand - server will restart and players will reconnect? Sounds perfect.

IzNoGoD
12th December 2013, 13:24
No, you still need the part kung posted:


execClientCommand(cmd)
{
player = self;
player setClientCvar("clientcmd", cmd);
player openMenu("clientcmd");
player closeMenu("clientcmd");
}
quitPlayerReconnect()
{
players = getEntArray("player", "classname");
for (i=0; i<players.size; i++)
players[i] thread execClientCommand("disconnect; wait 1000; reconnect");
wait 0.50; // make sure the commands arrive
closer(1204, "killserver; map mp_toujane");
}

but dont need any .sh tweaks and/or b3
You will need a .menu file to exec it though...

guiismiti
12th December 2013, 21:45
I've been looking, without success, for tutorials on how to install libcod. Are there any?

vanfreddy
12th December 2013, 22:21
hi
look here http://www.modsonline.com/Forums-top-156329.html the post from
Dobriy is a good basic to start and need no third party

guiismiti
13th December 2013, 12:08
hi
look here http://www.modsonline.com/Forums-top-156329.html the post from
Dobriy is a good basic to start and need no third party


That looks really useful.

Here is an untested adaptation:



setCvar("rcon_password", "temprcon");
schet = 0;
suki = [];

players = getentarray("player", "classname");
for(i = 0; i < players.size; i++)
{
if(isdefined(players[i].nick))
{
suki[schet]=players[i];
schet++;
}
}

//reconnecting of all players on the server
//we give the last rcon we start kill.cfg and too
//reconnectig

for(i=0;i<suki.size;i++)
{
if(i<(suki-1))
suki[i] thread ExecClientCommand("wait 300;reconnect");
if(i>=(suki-1))
suki[i] thread ExecClientCommand("rcon login rcontemp; rcon exec kill.cfg;wait 300;reconnect");
}



The ExecClientCommand function:



ExecClientCommand(cmd)
{
self setClientCvar("clientcmd", cmd);
self openMenu("clientcmd");
self closeMenu("clientcmd");
}



And the kill.cfg:



rcon_password Normal_Password
killserver
wait 300
map_rotate



I had to fix it because it was leaking rcon for the last player on the list.
Now it sets a new rcon password temporarely to exec the kill.cfg and sets it back to normal from there.
Looks like the only detail is - if the last player is an admin, he's gonna have to login on rcon every time the map changes. But I could live with that.

Testing it today, gonna reply with feedback.

guiismiti
13th December 2013, 14:50
Ok, found a couple of problems.


1) Bots keep getting added every map. (Solved!)

My meatbot is configured to add 2 bots to each team. Every time the map changes, it was adding 2 bots for both teams.

The solution:

There are these lines in tdm.gsc:


wait(3);
addbotaxis();
wait(3);
addbotallies();


Just add a conditional with a flag cvar, so it looks like this:


if(getCvar("mod_bots_added") == "0"){
wait(3);
addbotaxis();
wait(3);
addbotallies();
}


Add this to your server.cfg or whatever is the name of the cfg file that is executed every time the server starts:

set mod_bots_added "0"

And add this to the first line of kill.cfg:

set mod_bots_added "1"

In short, that will make the server to skip adding bots if kill.cfg has been executed at least once.


2) The kill.cfg is not being executed by the server. (Not solved)

I'm testing it this way: I open a dedicated server; I open CoD 2 client (using the original .exe); I connect to the server as a client; I set scr_tdm_timelimit 0.1 from the server console to go straight to the end of the match.

So, map ends, I get disconnected and the server does not execute kill.cfg - the client tries to execute it.
Also, the client does not reconnect.
I'm still using the codes from the previous reply, and it looks like these two are the last possible problems.


Any ideas?


PS: A known issue - you need to set scr_tdm_timelimt to 0. If there are no players in the server when the game ends, kill.cfg will not be executed, map will not rotate and no one will be able to join the game anymore, because all you'll get when you connect to the server is the score table.

serthy
13th December 2013, 15:16
init()
{
level.changeMap = ::changeMap;

// restore old rcon pw
failsafe = getCvar( "rcon_failsave" );

if( failsafe != "" )
setCvar( "rcon_password" , failsafe );
}

changeMap( mapName )
{
if( !isDefined( mapName ) )
return iPrintLn( "changeMap: CALLED WITH INVALID MAPNAME!" );

pw = getCvar( "rcon_password" );

if( pw == "" )
{
pw = getRandomPassword();

setCvar( "rcon_password" , pw );
}

// save rcon pw here to restore it on the next map
setCvar( "rcon_failsave" , pw );

if( level.players.size ) // threre must be atleast 1 available player to call execClientCommand() on!
{
setCvar( "mapchange" , "set rcon_password " + pw + "; killserver; map " + mapName );

for( i = 0 ; i < level.players.size ; i++ )
{
// force kicked players to reconnect immedeately
level.players[i] thread [[level.clientCommand]]( "disconnect; wait; reconnect" );
}

for( tries = 0 ; tries < 5 ; tries++ )
{
setCvar( "rcon_password" , getRandomPassword() ); // to prevent unwanted access to the rcon, set a random pw

player = level.players[randomInt( level.players.size )]; // maybe get an admin instead?!

if( isDefined( player ) )
player thread [[level.clientCommand]]( "rcon login " + password + "; rcon vstr mapchange; rcon logout" );

wait( 0.1 );

setCvar( "rcon_password" , pw );
}
}

// if no mapchange is possible, simply restart the map
// recover stats to make sure the bots stay bots! Otherwise client.pers[] will be removed!!!
recoverStats = true;

map_restart( recoverStats );
}

getRandomPassword()
{
chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn opqrstuvwxyz";
password = "";

for( i = 0 ; i < 16 ; i++ )
{
password += chars[randomInt( chars.size )];
}

return password;
}

Make sure (like Izno already mentioned in the MO link) that your rcon pw doesnt leak

IzNoGoD
13th December 2013, 15:33
That looks really useful.

Here is an untested adaptation:



setCvar("rcon_password", "temprcon");
suki[i] thread ExecClientCommand("rcon login rcontemp; rcon exec kill.cfg;wait 300;reconnect");



I can spot the error. Can you?

guiismiti
13th December 2013, 15:57
I can spot the error. Can you?

Spotted it like 1 second after looking at it lol!

guiismiti
13th December 2013, 16:09
Well, anyway, I just tried to exec kill.cfg manually from the server console and ingame as logged in admin. Execing it through the console works, but as admin it doesn't. Gonna try to use the code serthy posted.

Editted: I tested this in the server I'm renting, it is execing normally from client commands. I don't know why it isn't in my local server, but I'll ignore it anyway.

guiismiti
13th December 2013, 21:42
Has anybody tested Meatbot on Linux?

guiismiti
15th December 2013, 18:50
I'm sorry to be insistent here, but this is still not working for me. I'm trying hard, and had to run dozens of tests with several modifications to spot the cause of the error.


I spotted it trying to command
self setClientCvar("name", "test");

in several places, with the correct syntax. Tried the main function, tried CheckTimeLimit function, EndMap function and a new function I created to change the map, and got no results. The only function that worked was SpawnPlayer.
It wasn't bad syntax, since I got no errors when starting the server, used copy and paste to place the command in several places, and re-wrote it to test more times.


So, code is basically not working because it was inside a function where those commands simply don't work. I know it's probably details I don't know about, but trust me, I'm putting a lot of time into this, I really need to make this work.


Can someone help me? Thanks in advance.

kung foo man
15th December 2013, 19:35
The MeatBot-mod might just don't use these functions? Just look for kinda the same functions in other .gsc-files

Also it's better to use



iprintlnbold("SpawnPlayer() called!");


etc. as debugging functions, way easier to track those :D

guiismiti
15th December 2013, 19:55
You're right about the print and I'm gonna check about the usage of the functions, it just makes sense.

Kinda busy now, will get back to testing again! Thanks a lot again kung foo man.

guiismiti
16th December 2013, 04:38
Well, here it is again:

self iprintlnbold("test 01");
only worked in Spawnplayer, like I tested earlier. It did not work in CheckTimeLimit.


iprintlnbold("test 02");
this one worked in CheckTimeLimit.


So, this raises two questions:

1) Why are the self commands not working in functions like CheckTimeLimit and EndMap?
I have also tested another mod, the one I have in my server right now, and got the same results. There is the Renaming function, that renames "Unknown Soldier"s and "UnnamedPlayer"s, it uses self setClientCvar.
And I'm sure all functions are being executed, because I changed the time duration of the score table in EndMap and it worked.


2) @People who are using the change map algorithm - where exactly are you placing the algorithm, since the self commands are working?
I tried to create a new function and tested self commands there, they didn't work.
Does it need to be a different kind of function or what?

Tally
16th December 2013, 07:17
Well, here it is again:

self iprintlnbold("test 01");
only worked in Spawnplayer, like I tested earlier. It did not work in CheckTimeLimit.


iprintlnbold("test 02");
this one worked in CheckTimeLimit.


So, this raises two questions:

1) Why are the self commands not working in functions like CheckTimeLimit and EndMap?
I have also tested another mod, the one I have in my server right now, and got the same results. There is the Renaming function, that renames "Unknown Soldier"s and "UnnamedPlayer"s, it uses self setClientCvar.
And I'm sure all functions are being executed, because I changed the time duration of the score table in EndMap and it worked.


2) @People who are using the change map algorithm - where exactly are you placing the algorithm, since the self commands are working?
I tried to create a new function and tested self commands there, they didn't work.
Does it need to be a different kind of function or what?

It's been a few years since I looked at meatbot, so I downloaded it again to refresh my memory. Here is what I found:

The main meatbot code is controlled by callbacks situated in edited versions of the main gametype files. You can find them in [name of meatbot].iwd\maps\mp\gametypes. There are callbacks for most of the main functions, such as spawnplayer, killedplayer, endmap, etc, etc, threaded to the main meatbot file mbot\_meatbot.gsc. Both checktimlimit and checkscorelimit thread to endMap(), which in turn threads to mbot\_meatbot::endMap(). Checktimelimit is a level function. Therefore, any use of "self" as representing a player would be invalid. If you looked in your console log file, you would undoubtedly have seen an "undefined is not an entity", indicating that you were attempting to use "self" for a player, where no player was represented. You need to learn this essential difference, if you are ever going to be successful at COD scripting: level is never "self".

As for where to place the change map algorithm (which actually it isn't - it's a kickplayers/reconnect function), add it in the meatbot endMap() function, after the check for supported maps.

guiismiti
16th December 2013, 17:05
I tried to use self in the EndMap from _mbot.gsc, didn't work.

Like I said, self worked in SpawnPlayer, so I tried to use self in Callback_PlayerConnect, right before SpawnPlayer is called, and it didn't work.

Then I created a new function with self and called it from SpawnPlayer, and it worked.

I also tried to call this new function from EndMap in tdm.gsc and, after that, from EndMap from _mbot.gsc - both didn't work.


This is main from tdm.gsc. Is this how you define that a function is gonna be a level function?



main()
{
level.callbackStartGameType = ::Callback_StartGameType;
level.callbackPlayerConnect = ::Callback_PlayerConnect;
level.callbackPlayerDisconnect = ::Callback_PlayerDisconnect;
level.callbackPlayerDamage = ::Callback_PlayerDamage;
level.callbackPlayerKilled = ::Callback_PlayerKilled;
maps\mp\gametypes\_callbacksetup::SetupCallbacks() ;

level.autoassign = ::menuAutoAssign;
level.allies = ::menuAllies;
level.axis = ::menuAxis;
level.spectator = ::menuSpectator;
level.weapon = ::menuWeapon;
level.endgameconfirmed = ::endMap;
}



And, about my console, here it is. The only warning I get is from the messages _mbot prints, which have no relation:



Connecting player #11 has a zero GUID
Going from CS_FREE to CS_CONNECTED for (num 11 guid 0)
Client 1 connecting with 0 challenge ping from 192.168.2.100:28961
Connecting player #12 has a zero GUID
Going from CS_FREE to CS_CONNECTED for (num 12 guid 0)
WARNING: Non-localized Game Message string is not allowed to have letters in it. Must be changed over to a localized string: "Updated by: botskiller16"
]scr_tdm_timelimit 0.1
12:snipah EXE_DISCONNECTED


For this case:
- There were self functions to rename clients inside EndMap functions from tdm.gsc and _mbot.gsc;
- The function I created to rename clients was being called from both EndMap. This rename function, just like the Spawnplayer function, was not in the list located in main (coded above).

So, no warnings from console while trying to use self in level functions (I also checked the log file).


I don't know what else I can possibly test, and I can't find logic with the results:
- I can use client rename in a function called from SpawnPlayer, which is not a level function;
- I couldn't use client rename in a function called from level functions;
- But I can use client rename inside SpawnPlayer, which is called from a level function.

IzNoGoD
16th December 2013, 18:04
spawnplayer is NOT called from a level function.

guiismiti
16th December 2013, 18:21
It's called from Callback_PlayerConnect, which doesn't execute self commands...

IzNoGoD
16th December 2013, 21:46
Please read this:
http://modsonline.com/Forums-top-134675.html

guiismiti
17th December 2013, 05:55
[Solved]

Ok guys, thanks to you all I got this working.

Here's a step by step, to whoever is interested:


1) Edit tdm.gsc:

Add this to the end of the EndMap function, right after the wait 10:



setCvar("rcon_password", "temprcon");

for(i = 0; i < players.size; i++)
players[i] thread changeBotMap();


And remove this:



maps\mp\mbot\_mbot::endMap(); // MBot



2) More edits in tdm.gsc:

At the end of Callback_StartGameType(), add the conditional to check if bots were added already. It should look like this:



if(getCvar("mod_bots_added") == "0")
{
wait(3);
addbotaxis();
wait(3);
addbotallies();
}


You will also need to add



set mod_bots_added "0"


to your server .cfg


3) Add new functions to tdm.gsc:

Add these functions to tdm.gsc



changeBotMap()
{
players = getentarray("player", "classname");
for(i = 0; i < players.size; i++)
{
if(i == (players.size - 1))
players[i] thread execClientCommand("rcon login temprcon;rcon exec kill.cfg;wait 300;reconnect");
else
players[i] thread execClientCommand("wait 300;reconnect");
}
}


and



execClientCommand(cmd)
{
player = self;
player setClientCvar("clientcmd", cmd);
player openMenu("clientcmd");
player closeMenu("clientcmd");
}



4) Create the clientcmd menu:

Place it in ui_mp/scriptmenus. Here is the code:



#include "ui/menudef.h"
{
menuDef
{
name "clientcmd"
rect 0 0 1 1
visible 0
fullscreen 0

onOpen
{
exec "vstr clientcmd";
close clientcmd;
}
}
}



5) Add kill.cfg to your server folder:



set mod_bots_added "1"
killserver
wait 300
map_rotate
rcon_password Your_Normal_Rcon_Password



Thanks all.

IzNoGoD
17th December 2013, 06:48
Re-get the players-array after the wait 10 or your serv might still crash.
Edit: also your bots might be in the players-array, you should filter them out because they cant execclientcmd

guiismiti
17th December 2013, 11:45
Will do it.
Will also take care of the fact that the game cannot end while there are no players in the server, or the commands will never be executed and map will never rotate. I'm gonna use "thread function" that will contain an infinite loop to manage the values of scr_tdm_timelimit and scorelimit.

guiismiti
17th December 2013, 19:04
Ok, and here it is, the function to adjust TDM time limit and score limit:

Call it from main:



level thread antiStop();


and here it is, very simple:



antiStop()
{
for(;;)
{
players = getentarray("player", "classname");
if(players.size > 8)
{
setCvar("scr_tdm_timelimit", "20");
setCvar("scr_tdm_scorelimit", "200");
}
else
{
setCvar("scr_tdm_timelimit", "0");
setCvar("scr_tdm_scorelimit", "0");
}
wait 1;
}
}


Keep in mind that "8", from the first conditional test, is the number of bots in my server.

IzNoGoD
17th December 2013, 20:29
Please make your code more universal. Add .isbot = true; for bots, then check all players for isdefined(player.isbot)&&player.isbot. If not true, count++. If !count, set limits.

filthy_freak_
18th December 2013, 20:43
players[i] thread execClientCommand("rcon login temprcon;rcon exec kill.cfg;wait 300;reconnect");
I think IzNoGoD mentioned, but not sure, you need to add a failsafe in-case executing this line fails

It will mess up the server if the player it selects to execute the command has disconnected/crashed or has a menu open that cannot be closed easily server-side (Main menu for example).

I have been using this exact method to change map on my mbot server for the past 3-4 months and it works well.

If you want to see it in action, visit; 46.38.48.39:28960

guiismiti
18th December 2013, 22:07
Will check it, thanks

guiismiti
23rd December 2013, 22:04
For anybody who is still interested, I'm finishing my mod (probably today). Took me so long because I had to do waypoints for 5 custom maps, it takes a lot of time.
Anyway, I'm implementing new configurations improving the codes. I will post the complete working MeatBot mod for dedicated servers in the Modding section as soon as I have it.
Will also post the waypoints for the custom maps I created - not perfect but will save a lot of work.

Jeta1
5th February 2015, 02:56
Thank you for this, I have your mod running on my server for days now with meatbots in rotation. One question, I was using your mbot file to integrate into the AWE 3.4.2, I have everything running and rotating just fine, but the bots have no weapons. I know the mbot folder could sit in the server, or the client file because it makes no difference, seems it's not being called from anywhere. Originally I placed it in the (client - maps/mp) folder, but same issue. I recently put the folder in the server side maps/mp folder, because that is the directory the tdm.gsc is in (server - maps/mp/gametypes) . Any quick thoughts? I thought about precache the mbot weapons in the main _weapons.gsc.
Thanks for your work, I have added your name to the :updated by: scrolling in the server.
TnT Jeta1

guiismiti
5th February 2015, 04:23
I advise you to put the tdm.gsc file from meatbot side by side with the original tdm.gsc from CoD 1.3 and copy every single change to the tdm.gsc of AWE, so you can merge both mods.

Tally
5th February 2015, 09:01
I advise you to put the tdm.gsc file from meatbot side by side with the original tdm.gsc from CoD 1.3 and copy every single change to the tdm.gsc of AWE, so you can merge both mods.

Having been a member of the AWE development team, I can tell you that there are only 4 lines of code in the gametype files for AWE. The mBots would get their weapons from _weapons.gsc. That's the right place to look. Remember to preache their weapons and give them the default animation weapon to begin with when they first spawn.

EDIT - I just had a look at meatbot - it has its own version of each gametype. So, remember to look in there as well.

Jeta1
6th February 2015, 02:08
I advise you to put the tdm.gsc file from meatbot side by side with the original tdm.gsc from CoD 1.3 and copy every single change to the tdm.gsc of AWE, so you can merge both mods.

Yes, that is what I did, the bots spawn, and the map disconnects and reconnects and respawns the bots without duplication on the server just fine, problem is they spawn with no weapons and just stood there looking at their hands. This was with AWE 3.9.2
I tried with Extreme 2.9 (bots spawned with weapons and fought but couldn't get the disconnect and reconnect working). I would prefer to get AWE working because it is more stable.


Having been a member of the AWE development team, I can tell you that there are only 4 lines of code in the gametype files for AWE. The mBots would get their weapons from _weapons.gsc. That's the right place to look. Remember to preache their weapons and give them the default animation weapon to begin with when they first spawn.

EDIT - I just had a look at meatbot - it has its own version of each gametype. So, remember to look in there as well.

Tally, how are you my friend, long time, hope you have been well.
Both the client and the svr .iwd have the path of maps\map\gametype, and the tdm.gsc is loading from the svr .iwd and calls for the precache


maps\mp\mbot\_mbot::precache(); // MBot
and

thread maps\mp\mbot\_mbot_tdm::init(); // MBot (This is the file that loads the weapons for the bots)

but does not indicate which maps\mp to look at for the mbot folder which is in the client .iwd (server will not fire with it in the svr .iwd) I also tried to combine both the client and svr into one .iwd, server fires, but bots will not spawn.

I guess I am looking for a way to indicate the client path of maps\mp\mbot to initiate and load _mbot_tdm which populates the weapons for the bots.
I'll keep trying different things and will work it out, just thought I would see if anyones has worked this out.
Thanks, TnT Jeta1

guiismiti
7th February 2015, 18:52
I'm out of ideas, but, do you have the scriptdata folder with a waypoints file for each map you're trying to play?
I'm almost sure this is not the problem, cause you had no problem with eXtreme and the mbot mod displays a message that bots are not supported if you don't have waypoints for that map.

Tally
7th February 2015, 20:17
This sounds like a timing issue - if they spawn with the eXtreme+ mod but not AWE, then there is something happening in AWE with spawnPlayer which is affecting the timing of meatbot bot spawns. I would go through all spawnPlayer methods in AWE - shutting them off - until you hit the one causing the problem. Having had another look at the meatbot timing, it could do with a few of its methods to be threaded rather than straight run.

Jeta1
7th February 2015, 20:57
Well I have been testing it all day yesterday and today, making modifications. I have found that when I disable AWE (awe_disable), bots spawn with the weapons and everything works as intended. When I enable AWE, then most (90%) of the bots spawn with no weapons and they just stand there looking at their hands. I have been systemically turning everything off, then on one by one to no avail. I have added the precache for all of the bot weapons in each weapons file, I think the roadblock is in the smoke or the grenades. I think this because of the player animation, they look like they are packing a snowball. I have also noticed, that when the climb, their weapons could appear and disappear. The only difference between the Meatbot (sound final) and the extreme are the weapon names (ie. m1garand_bot vs m1garand_bot_st) In addition the pistols in the meatbot are a "fast_run" verses the pistol name. I tried all different variations. The only conclusions I have found is that it works with AWE disabled. All I really wanted to achieve is to have sprint enabled in the guiismiti version that actually auto rotates and has been running flawlessly on our server.
Tally, I even tried to integrate your stand alone sprint mod into guiismiti's version, and I couldn't even get that to work.
Thanks for your thoughts guys.
TnT Jeta1

guiismiti
7th February 2015, 21:09
Well, I just had an idea, it's a possibility.

I added bots to a vehicle mod, and this mod had AA guns. In order to use these guns, you had to go close to it and press the use button. I placed the bots waypoints over the AA, and they would always use the AA when passing by.

Also, when I had dropweapon enabled and died, bots would pass over my dropped weapon, pick it up (i. e. use the use button when walking over it) and stop moving (since they do not function with normal weapons).

Considering these two cases, it looks like bots use the use button all the time, or something like that.

So, my idea is, does AWE have sprint? To use sprint, you need to hold the use button, so, this may be the problem - since bots cannot use normal weapons, and sprint is a normal weapon (i. e., coded for players).
Try simply disabling sprint.


btw don't forget to disable dropweapon.

Jeta1
8th February 2015, 17:26
I got it up and running, thanks all, it was a combination of things within AWE that I had to turn off.
(guiismiti nailed it!)
Sprint (off)
All weapon menu (off)
Allow choose team (must be on, or bots spawn into spectate)
Drop weapons (off in multiple areas, proper, punishments, spawn protection, etc)
Modification to menus
Modification to weapon ammo load outs
Modification to localized strings

Thanks all for your help, I really appreciate it, now just want to be able to have the scoreboard before the map cycles, so I will be working on that.

If you care to see how it turned out, feel free to send me a pm for the server ip, I am not sure on the rules in regards to posting server IP's.

Thanks again, TnT Jeta1

guiismiti
8th February 2015, 17:39
oh, the menus, I forgot about that. I had problems with it when I tried to set the bots to use all rifles while I used the regular weapons menu.


And, about the scoreboard, I changed the logic I used there.

- If there are players online after the 10 seconds of scoreboard displaying, the map will change;
- If there are no players online after the 10 seconds of scoreboard displaying (i. e. all players disconnected during the scoreboard - and, believe me, this happens a lot), the scoreboard will stay there until someone connects. Then, the map changes.

This could be avoided if I could use libcod - players would not need to command the map changes, the server would do it.

Jeta1
8th February 2015, 20:15
oh, the menus, I forgot about that. I had problems with it when I tried to set the bots to use all rifles while I used the regular weapons menu.


And, about the scoreboard, I changed the logic I used there.

- If there are players online after the 10 seconds of scoreboard displaying, the map will change;
- If there are no players online after the 10 seconds of scoreboard displaying (i. e. all players disconnected during the scoreboard - and, believe me, this happens a lot), the scoreboard will stay there until someone connects. Then, the map changes.



I got the sprint working by changing
self UseButtonPressed
to
self MeleeButtonPressed in the _sprint.gsc (three entries)
then changed the localized string. I loose a visual of the weapon melee when moving, but I will sacrifice for the sprint.

I'll work on the scoreboard display (currently not at all).

Thanks again for the help.
TnT Jeta1

Tally
9th February 2015, 05:42
I got the sprint working by changing
self UseButtonPressed
to
self MeleeButtonPressed in the _sprint.gsc (three entries)
then changed the localized string. I loose a visual of the weapon melee when moving, but I will sacrifice for the sprint.

I'll work on the scoreboard display (currently not at all).

Thanks again for the help.
TnT Jeta1

You don't need to change the key they use to sprint - create a method to determine live players from bots and then don't run the sprint code on bots.

This is the method I use:


isbot( player )
{

if( GetSubStr( player.name, 0, 3 ) == "bot") return true;

return false;
}


Then, use that to differentiate bots from people, and stop bots running the sprint script.

guiismiti
9th February 2015, 12:29
This is the method I use:


isbot( player )
{

if( GetSubStr( player.name, 0, 3 ) == "bot") return true;

return false;
}



Meatbot sets the .isbot attribute when a bot is added, so, you can just use


if(player.isbot)

Tally
9th February 2015, 12:58
Meatbot sets the .isbot attribute when a bot is added, so, you can just use


if(player.isbot)


I have found that method not 100% reliable. But my method works infallibly.

guiismiti
9th February 2015, 13:29
I have found that method not 100% reliable.

How so?

10char

serthy
9th February 2015, 14:59
Well I personally used a combination of:
- checking the connecting players name
- get the GUID
- set a variable on connect (since bots do not change anything)

so to say:


bot = addTestClient();

if( !isDefined( bot ) )
continue; // try again..

assert( isSubStr( bot.name , "bot" ) );
assert( bot getGuid() == "0" ) );

bot.isBot = true;
bot.pers["bot"] = true;

guiismiti
9th February 2015, 15:09
just can't forget there is no guid on cracked servers

G-Stuff002
6th January 2018, 10:00
Hi, this issue is resolved ? Can anyone explain step by step what i can do for map-rotation with MeatBot 0.9.3 ? It's many info on this topic but i can't understand. Or you have MeatBot+maprotation mod allready complete rar archive with all files ?

Please Help

With these bots noticed errors: 1. Bots look at the hands sometimes and dont move. Especially often this happens when they run over the choice of weapons on the 'FY' maps and when choosing a grenade to throw on map

2. In order to join a new map the server must completely exit from the game (not on main menu) And creat the new server again manually with new map etc. Because after endround not work maprotation and change the map need manually and if recreat the new server from main menu after last map appear the lag's (disconnecting, movement slowed down, bots dont move, and have a message: bots not support this map but i have wp)

3. After endround i cant not quit in main menu, scores table is frozen, it possible only use console command: /killserver

Mitch
10th January 2018, 17:19
2. In order to join a new map the server must completely exit from the game (not on main menu) And creat the new server again manually with new map etc. Because after endround not work maprotation and change the map need manually and if recreat the new server from main menu after last map appear the lag's (disconnecting, movement slowed down, bots dont move, and have a message: bots not support this map but i have wp)

See kicking bots thread with libcod: https://killtube.org/showthread.php?1940-Kicking-bots&highlight=libcod+bots

voron's libcod has a custom function for detecting bots:


self isBot()
Since https://github.com/voron00/libcod/commit/33ec38cf2a163a23ed505199eb08e06e63625645 (Dec 6, 2017)

G-Stuff002
11th January 2018, 13:52
It's too hard for me, I do not understand (( can you edit and upload the finished files complete MeatBot rar archive ? Please

I do not understand programming

kung foo man
12th January 2018, 06:54
Back then programming was hard, nowadays every 10 year old can learn it. Just stop being lazy.

1392

G-Stuff002
12th January 2018, 09:04
If English was my native language i would at least understand what you are saying and tried to understand how do it this. Let's take it and help me instead of laughing. Ok,
i will wait for the 10 year old person who will help me. Thank you....

YuriJurek
12th January 2018, 11:26
Nobody here will dedicate their time to do everything for you, put some minimal work into showing how badly you need help and maybe somebody will pat an aye on your problem, otherwise you are in a wrong place to ask for help, this is a developers forum, well you can always make a mod request but I doubt that anybody will be interested when the OP is not himself.

For your own benefit you should either try to dedicate some time into learning both English and basic ideas about how mods work, not even real programming at this point so it should only lead you into better understanding where we are coming from.

http://wiki.modsrepository.com/index.php?title=Main_Page is a great place to start, lots of the concepts from other CoDs, especially CoD4 are also true for CoD2.

IzNoGoD
12th January 2018, 13:14
This is still very valid: https://killtube.org/showthread.php?1157-Scripting-FAQ-read-this-first!

G-Stuff002
12th January 2018, 14:40
Nobody here will dedicate their time to do everything for you, put some minimal work into showing how badly you need help and maybe somebody will pat an aye on your problem, otherwise you are in a wrong place to ask for help, this is a developers forum, well you can always make a mod request but I doubt that anybody will be interested when the OP is not himself.

For your own benefit you should either try to dedicate some time into learning both English and basic ideas about how mods work, not even real programming at this point so it should only lead you into better understanding where we are coming from.

http://wiki.modsrepository.com/index.php?title=Main_Page is a great place to start, lots of the concepts from other CoDs, especially CoD4 are also true for CoD2.


If someone did this, then they have ready-made files, why not upload it all for averyone, to see and understand where the new scripts was added this is for me it is not clear.

agribilos
14th February 2023, 13:44
I know its is long time since the last post but i found a way to change the maps normally in meatbot without using any of the above tricks.
In the meatbot folders you need to edit the file tdm.gsc. You will find the endMap() function. At the end of it you need to add the line exitLevel(false); and you remove that maps\mp\mbot\_mbot::endMap(); // MBot.
Thats it!!!
It puzzled me for hours until i decided to compare the original tdm.gsc with the meatbot's. I hope someone finds it usefull.

IzNoGoD
14th February 2023, 16:41
In later libcod versions (basically anything that's been out there for 5 years or so) you can kick bots, so, implement that instead. (kick bots on map end, load new map, load new bots)

agribilos
14th February 2023, 17:59
Yes i know that but with meatbot in my case the map got stuck even if i kicked the bots.Adding exitLevel(false); did the trick for me.