Usage
the commands pretty much explain themself, except !start
!start without any arguments will start a bo1 on the current map
!start de_cache will start a bo1 on cache and will load the map
!start de_cache de_dust2 de_dust will start a bo3
you can also play bo2 or bo4 which obviously can result in a draw
Installation
Download the zip file and place the configs and smx file according to the hierarchy in the zip file
If you discover any bugs or have suggestions please post them here
Have fun!
TODO
!test command needs to display correct botname
translation files
money notification in chat
chat-aliases for commands
change teamnames
veto system
Changelog
Spoiler
v1.1
- switched to transitional syntax
v1.2
- added command to change team names (!team1name xxx , !team2name xxx)
- when changing variables like knife or overtime they now get saved to config
- !knife and !overtime now only changable during warmup
public PlVers:__version = { version = 5, filevers = "1.8.0.5969", date = "02/09/2017", time = "14:12:35" }; new Float:NULL_VECTOR[3]; new String:NULL_STRING[4]; public Extension:__ext_core = { name = "Core", file = "core", autoload = 0, required = 0, }; new MaxClients; public Extension:__ext_cstrike = { name = "cstrike", file = "games/game.cstrike.ext", autoload = 0, required = 1, }; new String:g_botName[512] = "Mara\x04Bot"; new String:g_ctName[128]; new String:g_tName[128]; new String:g_mapPool[9][128]; new bool:g_botActive; new bool:g_knife = 1; new bool:g_knifedone; new bool:g_overtime = 1; new bool:g_warmup; new bool:g_ct_ready; new bool:g_t_ready; new bool:g_abort; new bool:g_live; new bool:g_paused; new bool:g_ctRmvPause; new bool:g_tRmvPause; new bool:g_staySwitchDone; new bool:g_printScore; new bool:g_switcher; new g_maxRounds = 30; new g_otStartmoney = 10000; new g_otRounds = 6; new g_boX = 1; new g_mapCount = 1; new g_wonKnife; new g_roundsstarted; new g_otswitcher; new g_mapWinner; new g_team1score; new g_team2score; new Handle:Timer_warmupHandle; new Handle:Timer_CountdownHandle; new Handle:Timer_pauseHandle; new Handle:Timer_staySwitchHandle; public Plugin:myinfo = { name = "MaraBot v1.0", description = "This Bot handles competitive Games", author = "Luca Heft", version = "1.0", url = "http://www.mara-esports.de/" }; public void:__ext_core_SetNTVOptional() { MarkNativeAsOptional("GetFeatureStatus"); MarkNativeAsOptional("RequireFeature"); MarkNativeAsOptional("AddCommandListener"); MarkNativeAsOptional("RemoveCommandListener"); MarkNativeAsOptional("BfWriteBool"); MarkNativeAsOptional("BfWriteByte"); MarkNativeAsOptional("BfWriteChar"); MarkNativeAsOptional("BfWriteShort"); MarkNativeAsOptional("BfWriteWord"); MarkNativeAsOptional("BfWriteNum"); MarkNativeAsOptional("BfWriteFloat"); MarkNativeAsOptional("BfWriteString"); MarkNativeAsOptional("BfWriteEntity"); MarkNativeAsOptional("BfWriteAngle"); MarkNativeAsOptional("BfWriteCoord"); MarkNativeAsOptional("BfWriteVecCoord"); MarkNativeAsOptional("BfWriteVecNormal"); MarkNativeAsOptional("BfWriteAngles"); MarkNativeAsOptional("BfReadBool"); MarkNativeAsOptional("BfReadByte"); MarkNativeAsOptional("BfReadChar"); MarkNativeAsOptional("BfReadShort"); MarkNativeAsOptional("BfReadWord"); MarkNativeAsOptional("BfReadNum"); MarkNativeAsOptional("BfReadFloat"); MarkNativeAsOptional("BfReadString"); MarkNativeAsOptional("BfReadEntity"); MarkNativeAsOptional("BfReadAngle"); MarkNativeAsOptional("BfReadCoord"); MarkNativeAsOptional("BfReadVecCoord"); MarkNativeAsOptional("BfReadVecNormal"); MarkNativeAsOptional("BfReadAngles"); MarkNativeAsOptional("BfGetNumBytesLeft"); MarkNativeAsOptional("BfWrite.WriteBool"); MarkNativeAsOptional("BfWrite.WriteByte"); MarkNativeAsOptional("BfWrite.WriteChar"); MarkNativeAsOptional("BfWrite.WriteShort"); MarkNativeAsOptional("BfWrite.WriteWord"); MarkNativeAsOptional("BfWrite.WriteNum"); MarkNativeAsOptional("BfWrite.WriteFloat"); MarkNativeAsOptional("BfWrite.WriteString"); MarkNativeAsOptional("BfWrite.WriteEntity"); MarkNativeAsOptional("BfWrite.WriteAngle"); MarkNativeAsOptional("BfWrite.WriteCoord"); MarkNativeAsOptional("BfWrite.WriteVecCoord"); MarkNativeAsOptional("BfWrite.WriteVecNormal"); MarkNativeAsOptional("BfWrite.WriteAngles"); MarkNativeAsOptional("BfRead.ReadBool"); MarkNativeAsOptional("BfRead.ReadByte"); MarkNativeAsOptional("BfRead.ReadChar"); MarkNativeAsOptional("BfRead.ReadShort"); MarkNativeAsOptional("BfRead.ReadWord"); MarkNativeAsOptional("BfRead.ReadNum"); MarkNativeAsOptional("BfRead.ReadFloat"); MarkNativeAsOptional("BfRead.ReadString"); MarkNativeAsOptional("BfRead.ReadEntity"); MarkNativeAsOptional("BfRead.ReadAngle"); MarkNativeAsOptional("BfRead.ReadCoord"); MarkNativeAsOptional("BfRead.ReadVecCoord"); MarkNativeAsOptional("BfRead.ReadVecNormal"); MarkNativeAsOptional("BfRead.ReadAngles"); MarkNativeAsOptional("BfRead.GetNumBytesLeft"); MarkNativeAsOptional("PbReadInt"); MarkNativeAsOptional("PbReadFloat"); MarkNativeAsOptional("PbReadBool"); MarkNativeAsOptional("PbReadString"); MarkNativeAsOptional("PbReadColor"); MarkNativeAsOptional("PbReadAngle"); MarkNativeAsOptional("PbReadVector"); MarkNativeAsOptional("PbReadVector2D"); MarkNativeAsOptional("PbGetRepeatedFieldCount"); MarkNativeAsOptional("PbSetInt"); MarkNativeAsOptional("PbSetFloat"); MarkNativeAsOptional("PbSetBool"); MarkNativeAsOptional("PbSetString"); MarkNativeAsOptional("PbSetColor"); MarkNativeAsOptional("PbSetAngle"); MarkNativeAsOptional("PbSetVector"); MarkNativeAsOptional("PbSetVector2D"); MarkNativeAsOptional("PbAddInt"); MarkNativeAsOptional("PbAddFloat"); MarkNativeAsOptional("PbAddBool"); MarkNativeAsOptional("PbAddString"); MarkNativeAsOptional("PbAddColor"); MarkNativeAsOptional("PbAddAngle"); MarkNativeAsOptional("PbAddVector"); MarkNativeAsOptional("PbAddVector2D"); MarkNativeAsOptional("PbRemoveRepeatedFieldValue"); MarkNativeAsOptional("PbReadMessage"); MarkNativeAsOptional("PbReadRepeatedMessage"); MarkNativeAsOptional("PbAddMessage"); MarkNativeAsOptional("Protobuf.ReadInt"); MarkNativeAsOptional("Protobuf.ReadFloat"); MarkNativeAsOptional("Protobuf.ReadBool"); MarkNativeAsOptional("Protobuf.ReadString"); MarkNativeAsOptional("Protobuf.ReadColor"); MarkNativeAsOptional("Protobuf.ReadAngle"); MarkNativeAsOptional("Protobuf.ReadVector"); MarkNativeAsOptional("Protobuf.ReadVector2D"); MarkNativeAsOptional("Protobuf.GetRepeatedFieldCount"); MarkNativeAsOptional("Protobuf.SetInt"); MarkNativeAsOptional("Protobuf.SetFloat"); MarkNativeAsOptional("Protobuf.SetBool"); MarkNativeAsOptional("Protobuf.SetString"); MarkNativeAsOptional("Protobuf.SetColor"); MarkNativeAsOptional("Protobuf.SetAngle"); MarkNativeAsOptional("Protobuf.SetVector"); MarkNativeAsOptional("Protobuf.SetVector2D"); MarkNativeAsOptional("Protobuf.AddInt"); MarkNativeAsOptional("Protobuf.AddFloat"); MarkNativeAsOptional("Protobuf.AddBool"); MarkNativeAsOptional("Protobuf.AddString"); MarkNativeAsOptional("Protobuf.AddColor"); MarkNativeAsOptional("Protobuf.AddAngle"); MarkNativeAsOptional("Protobuf.AddVector"); MarkNativeAsOptional("Protobuf.AddVector2D"); MarkNativeAsOptional("Protobuf.RemoveRepeatedFieldValue"); MarkNativeAsOptional("Protobuf.ReadMessage"); MarkNativeAsOptional("Protobuf.ReadRepeatedMessage"); MarkNativeAsOptional("Protobuf.AddMessage"); VerifyCoreVersion(); return void:0; }
public .2920.StrCat(String:buffer[], maxlength, String:source[]) { new len = strlen(buffer); if (len >= maxlength) { return 0; } return Format(buffer[len], maxlength - len, "%s", source); }
public .2920.StrCat(String:buffer[], maxlength, String:source[]) { new len = strlen(buffer); if (len >= maxlength) { return 0; } return Format(buffer[len], maxlength - len, "%s", source); }
public .3096.ExplodeString(String:text[], String:split[], String:buffers[][], maxStrings, maxStringLength, bool:copyRemainder) { new reloc_idx; new idx; new total; new var1; if (maxStrings < 1 || !split[0]) { return 0; } while ((idx = SplitString(text[reloc_idx], split, buffers[total], maxStringLength)) != -1) { reloc_idx = idx + reloc_idx; total++; if (maxStrings == total) { if (copyRemainder) { strcopy(buffers[total + -1], maxStringLength, text[reloc_idx - idx]); } return total; } } total++; strcopy(buffers[total], maxStringLength, text[reloc_idx]); return total; }
public .3096.ExplodeString(String:text[], String:split[], String:buffers[][], maxStrings, maxStringLength, bool:copyRemainder) { new reloc_idx; new idx; new total; new var1; if (maxStrings < 1 || !split[0]) { return 0; } while ((idx = SplitString(text[reloc_idx], split, buffers[total], maxStringLength)) != -1) { reloc_idx = idx + reloc_idx; total++; if (maxStrings == total) { if (copyRemainder) { strcopy(buffers[total + -1], maxStringLength, text[reloc_idx - idx]); } return total; } } total++; strcopy(buffers[total], maxStringLength, text[reloc_idx]); return total; }
public .3700.PrintToChatAll(String:format[]) { new String:buffer[256]; new i = 1; while (i <= MaxClients) { if (IsClientInGame(i)) { SetGlobalTransTarget(i); VFormat(buffer, 254, format, 2); PrintToChat(i, "%s", buffer); } i++; } return 0; }
public .3700.PrintToChatAll(String:format[]) { new String:buffer[256]; new i = 1; while (i <= MaxClients) { if (IsClientInGame(i)) { SetGlobalTransTarget(i); VFormat(buffer, 254, format, 2); PrintToChat(i, "%s", buffer); } i++; } return 0; }
public Action:Timer_staySwitch(Handle:timer) { if (g_staySwitchDone) { Timer_staySwitchHandle = MissingTAG:0; return Action:4; } sayToChat("Type !stay\x01 or !switch\x01 to decide your starting team."); return Action:0; }
public Action:Timer_Countdown(Handle:timer) { static numPrinted = 10; if (g_abort) { numPrinted = 10; Timer_warmupHandle = CreateTimer(10.0, Timer_warmup, any:0, 1); Timer_CountdownHandle = MissingTAG:0; return Action:4; } if (numPrinted < 1) { numPrinted = 10; Timer_CountdownHandle = MissingTAG:0; startGame(); return Action:4; } new String:msg[128]; Format(msg, 128, "Match will start in %d seconds. Type !abort to abort Countdown.", numPrinted); sayToChat(msg); numPrinted -= 1; return Action:0; }
public Action:Timer_warmup(Handle:timer) { if (!g_warmup) { Timer_warmupHandle = MissingTAG:0; return Action:4; } sayToChat("Type !ready\x01 in order to start the game."); new Handle:CVarCTName; new Handle:CVarTName; new String:t_ctname[128]; new String:t_tname[128]; CVarCTName = FindConVar("mp_teamname_1"); CVarTName = FindConVar("mp_teamname_2"); GetConVarString(CVarCTName, t_ctname, 128); GetConVarString(CVarTName, t_tname, 128); CloseHandle(CVarCTName); CloseHandle(CVarTName); new String:msg[128]; .2920.StrCat(msg, 128, t_ctname); if (g_ct_ready) { .2920.StrCat(msg, 128, " (\x04CT\x01) - "); } else { .2920.StrCat(msg, 128, " (\x07CT\x01) - "); } .2920.StrCat(msg, 128, t_tname); if (g_t_ready) { .2920.StrCat(msg, 128, " (\x04T\x01)"); } else { .2920.StrCat(msg, 128, " (\x07T\x01)"); } sayToChat(msg); return Action:0; }
public Action:Timer_pause(Handle:timer) { if (!g_paused) { Timer_pauseHandle = MissingTAG:0; return Action:4; } new Handle:CVarCTName; new Handle:CVarTName; new String:temp_team1name[128]; new String:temp_team2name[128]; CVarCTName = FindConVar("mp_teamname_1"); CVarTName = FindConVar("mp_teamname_2"); GetConVarString(CVarCTName, temp_team1name, 128); GetConVarString(CVarTName, temp_team2name, 128); CloseHandle(CVarCTName); CloseHandle(CVarTName); new String:msg[128]; new var1; if ((g_roundsstarted > g_maxRounds / 2 && g_roundsstarted <= g_otRounds / 2 + g_maxRounds) || g_switcher) { .2920.StrCat(msg, 128, temp_team2name); } else { .2920.StrCat(msg, 128, temp_team1name); } if (g_ctRmvPause) { .2920.StrCat(msg, 128, " (\x04CT\x01) - "); } else { .2920.StrCat(msg, 128, " (\x07CT\x01) - "); } new var3; if ((g_roundsstarted > g_maxRounds / 2 && g_roundsstarted <= g_otRounds / 2 + g_maxRounds) || g_switcher) { .2920.StrCat(msg, 128, temp_team1name); } else { .2920.StrCat(msg, 128, temp_team2name); } if (g_tRmvPause) { .2920.StrCat(msg, 128, " (\x04T\x01)"); } else { .2920.StrCat(msg, 128, " (\x07T\x01)"); } sayToChat("Type !unpause\x01 to remove the pause."); sayToChat(msg); return Action:0; }
public Action:sayToChat(String:msg[]) { new Handle:data = CreateDataPack(); WritePackString(data, msg); CreateTimer(0.1, sayToChatTimer, data, 0); return Action:0; }
bo# setting looks very good, long wait for it on warmod/pug setup, maybe i'll test your pug, and maybe this is be better when warmod/pug setup
From first look - looks like eBot, but more lightweight, and w/o web service
Good luck with this plugin
First:
I renamed bot in MaraBot.cfg "botName", but when i type on server "!test" it still say's default botname
in code
sayToChat("MaraBot works!");
Maybe set detect botname on MaraBot.cfg ?
Second:
No translation file
Third:
Need teammates money notification in chat
And can you make config for changing chat-alliases
like !ready to !r /r, !knife to !kf, and admin can add himself allies by himself (like on pugsetup, it's very usefull)
Also, give to players functional to change their teamnames by !t TEAMNAME1 , !ct TEAMNAME2
And very-very wait veto-system on match
Player/Admin before match start type !veto, choosing veto-style (bo3) for example, starts knife round and who win will pick or ban maps (pick-ban system of every best of_ type must choosed by admin on config), because there is 2 or 3 different veto-systems on any tournament's
This is need for tournament's only, and you can make it on or off in config, because on mix it don't need
First:
I renamed bot in MaraBot.cfg "botName", but when i type on server "!test" it still say's default botname
in code
sayToChat("MaraBot works!");
Maybe set detect botname on MaraBot.cfg ?
yes this is hardcoded, i will change it in the next version
Quote:
Originally Posted by waylander3
Second:
No translation file
Third:
Need teammates money notification in chat
And can you make config for changing chat-alliases
like !ready to !r /r, !knife to !kf, and admin can add himself allies by himself (like on pugsetup, it's very usefull)
Also, give to players functional to change their teamnames by !t TEAMNAME1 , !ct TEAMNAME2
added to TODO
i will also add the veto system to TODO this may come sooner or later
Quote:
Originally Posted by waylander3
Can you make per-player Ready system with info in HUD?
because now 1 player in each team can type !ready, and his team marked as ready.
wont do that for now cause this plugin is meant to be played by 2 full teams so no need to have ready for every person -> i changed the pug in the title and description (my fault)
yes this is hardcoded, i will change it in the next version
wont do that for now cause this plugin is meant to be played by 2 full teams so no need to have ready for every person
Thats good, but players, who playing on warmod/pug setup/etc remember, what they need to type !ready, but now this is mark they team instantly
Example:
On server 7 players
1 player joined CT (they are 5), and type !ready - they marked as ready
1 player joinned T (they are 4), and type !ready - they marked as ready
And match will start with 5v4?
And found 1 bug:
I renamed T to ATTACK, and CT to DEFENCE, we played Knife round (started on T), win knife, and typing !swap - on first half in chat and TAB we (ct) were marked as ATTACK
And found 1 bug:
I renamed T to ATTACK, and CT to DEFENCE, we played Knife round (started on T), win knife, and typing !swap - on first half in chat and TAB we (ct) were marked as ATTACK
thats exactly how this should work if you switch sides the names on scoreboard will also switch or am i getting something wrong?
CT - Team Pros
T - Team Noobs
after kniferound switch:
CT - Team Noobs
T - Team Pros
and yes it will start a 5v4 you will have to abort then and set your ready state again