-
Notifications
You must be signed in to change notification settings - Fork 0
Bot integration help
Dreamy Cecil edited this page May 27, 2024
·
7 revisions
At this time it is not recommended to integrate code from this project into your mods! One of the major reasons is incompatibility with Serious Sam Classics Patch due to its own network functionality that conflicts with the bot mod and may cause undefined behavior!
This document should walk you through simple steps that will help you integrate bots into your own mod.
Keep in mind that if your mod has many drastic changes to gameplay mechanics, don't be afraid of rewriting the bot code to your liking.
-
[Cecil] <date>
- indicates specifically when a certain feature has been implemented. -
[Cecil] TEMP
- temporary feature that can be applied permanently or removed at a later time. -
[Cecil] TODO
- notes to self about features that need to be implemented. -
[Cecil] NOTE
- important note about a certain feature. Advised to search for them for extra help with integration.
-
Bots
folder should be present at the very root of mod sources (alongside Engine, EntitiesMP etc.). -
Bots/_BotMod.h
is included inStdH.h
in EntitiesMP (at the end) and inStdAfx.h
in GameMP (replacingEntitiesMP/Player.h
).
- Include
BotModGlobal.es
,NavMeshGenerator.es
andPlayerBot.es
entities in your project and copy the custom build step. - All instances of
GetMaxPlayers()
andGetPlayerEntity()
are replaced withCECIL_GetMaxPlayers()
andCECIL_GetPlayerEntity()
respectively. - All instances of
IsOfClass(<ptr>, "Player")
andIsDerivedFromClass(<ptr>, "Player")
are replaced withIS_PLAYER(<ptr>)
. Can be achieved automatically by replacing, "Player")
with)
and then fixing errors where they appear. - All instances of
GetMyPlayerIndex()
are replaced withCECIL_PlayerIndex(<ptr>)
.- If it's just
GetMyPlayerIndex()
, it's replaced withCECIL_PlayerIndex(this)
. - If it's
ptr->GetMyPlayerIndex()
, it's replaced withCECIL_PlayerIndex(ptr)
.
- If it's just
- All
Player.es
additions that are on top of the vanillaPlayer.es
(commented with// [Cecil]
). - Also optional additions that are on top of the vanilla
Common/HUD.cpp
for making bots appear in the player list (also commented with// [Cecil]
).
- Initialization function at the end of
CGame::InitInternal()
:CECIL_InitBotMod();
- End function at the end of
CGame::EndInternal()
:CECIL_EndBotMod();
- Bot game start function in
CGame::NewGame()
right after the_pNetwork->StartPeerToPeer_t
call:CECIL_BotGameStart(sp);
- Bot game cleanup at the very beginning of
CGame::StopGame()
:CECIL_BotGameCleanup();
All of this takes place within the CGame::GameRedrawView()
function. See how it's implemented in this mod here.
- Create a container of player entities like so:
CDynamicContainer<CPlayer> cenPlayerEntities;
before these lines:
// fill in all players that are not local
INDEX ctNonlocals = 0;
- Remove this array after it:
CEntity *apenNonlocals[16];
memset(apenNonlocals, 0, sizeof(apenNonlocals));
-
Replace
apenNonlocals[ctNonlocals++] = pen;
withcenPlayerEntities.Add((CPlayer *)pen);
within thefor
loop. -
Add the following block after the
for
loop:
// [Cecil] Add bots
for (INDEX iBot = 0; iBot < _aPlayerBots.Count(); iBot++) {
CPlayerBot *penBot = (CPlayerBot *)_aPlayerBots[iBot].pen;
cenPlayerEntities.Add(penBot);
}
// [Cecil] Count non-local players
ctNonlocals = cenPlayerEntities.Count();
- Replace
apenViewers[ctViewers++] = apenNonlocals[iPlayer];
withapenViewers[ctViewers++] = cenPlayerEntities.Pointer(iPlayer);
within the nextfor
block.
Resulting block of code:
CDynamicContainer<CPlayer> cenPlayerEntities;
// fill in all players that are not local
INDEX ctNonlocals = 0;
{for (INDEX i=0; i<16; i++) {
CEntity *pen = CEntity::GetPlayerEntity(i);
if (pen!=NULL && !_pNetwork->IsPlayerLocal(pen)) {
cenPlayerEntities.Add((CPlayer *)pen);
}
}}
// [Cecil] Add bots
for (INDEX iBot = 0; iBot < _aPlayerBots.Count(); iBot++) {
CPlayerBot *penBot = (CPlayerBot *)_aPlayerBots[iBot].pen;
cenPlayerEntities.Add(penBot);
}
// [Cecil] Count non-local players
ctNonlocals = cenPlayerEntities.Count();
// if there are any non-local players
if (ctNonlocals>0) {
// for each observer
{for (INDEX i=0; i<ctObservers; i++) {
// get the given player with given offset that is not local
INDEX iPlayer = (i+iObserverOffset)%ctNonlocals;
apenViewers[ctViewers++] = cenPlayerEntities.Pointer(iPlayer);
}}
}