|
|
|
@ -42,6 +42,8 @@ using namespace RYAI_MAP_CRUNCH;
|
|
|
|
|
static bool VerboseLog = false;
|
|
|
|
|
#define LOG if (!VerboseLog) { } else nlinfo
|
|
|
|
|
|
|
|
|
|
extern CAIVector randomPos(double dispersionRadius);
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CSpawnBotNpc //
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
@ -64,14 +66,14 @@ void CSpawnBotNpc::sendInfoToEGS() const
|
|
|
|
|
{
|
|
|
|
|
if (!EGSHasMirrorReady)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CSpawnBot::sendInfoToEGS();
|
|
|
|
|
|
|
|
|
|
TGenNpcDescMsgImp msg;
|
|
|
|
|
msg.setEntityIndex(dataSetRow());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getPersistent().fillDescriptionMsg(msg);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg.setChat(_CurrentChatProfile);
|
|
|
|
|
msg.send("EGS");
|
|
|
|
|
}
|
|
|
|
@ -86,7 +88,7 @@ void CSpawnBotNpc::processEvent(CCombatInterface::CEvent const& event)
|
|
|
|
|
// no self aggro.
|
|
|
|
|
if (event._targetRow==event._originatorRow)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((event._nature==ACTNATURE::FIGHT || event._nature==ACTNATURE::OFFENSIVE_MAGIC) && !getPersistent().ignoreOffensiveActions())
|
|
|
|
|
{
|
|
|
|
|
float aggro = event._weight;
|
|
|
|
@ -116,7 +118,7 @@ void CSpawnBotNpc::processEvent(CCombatInterface::CEvent const& event)
|
|
|
|
|
{
|
|
|
|
|
++AISStat::BotTotalUpdCtr;
|
|
|
|
|
++AISStat::BotNpcUpdCtr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
H_AUTO(AIHpTrig);
|
|
|
|
|
// Fix for HP triggers
|
|
|
|
@ -136,7 +138,7 @@ void CSpawnBotNpc::processEvent(CCombatInterface::CEvent const& event)
|
|
|
|
|
_OldHpPercentage = getPhysical().hpPercentage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Bot chat and dyn chat override AI profile unless fighting
|
|
|
|
|
// The directing adjustment is done client-slide (each player sees the NPC facing him)
|
|
|
|
|
if (!getActiveChats().empty())
|
|
|
|
@ -156,10 +158,10 @@ void CSpawnBotNpc::processEvent(CCombatInterface::CEvent const& event)
|
|
|
|
|
if (sp)
|
|
|
|
|
{
|
|
|
|
|
sp->getPersistent().notifyStopNpcControl();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_PlayerController = NULL;
|
|
|
|
|
|
|
|
|
|
_PlayerController = NULL;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_PlayerController == NULL)
|
|
|
|
@ -186,16 +188,16 @@ void CSpawnBotNpc::processEvent(CCombatInterface::CEvent const& event)
|
|
|
|
|
// If sit and move then stand up
|
|
|
|
|
|
|
|
|
|
if (IsRingShard)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
if (getMode() == MBEHAV::SIT
|
|
|
|
|
&& (x().asInt() != startPos.x().asInt() || y().asInt() != startPos.y().asInt()) )
|
|
|
|
|
{
|
|
|
|
|
setMode(MBEHAV::NORMAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_FacingTick != 0)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
uint32 tick = CTimeInterface::gameCycle();
|
|
|
|
|
if ( (tick - _FacingTick) > 40)
|
|
|
|
|
{
|
|
|
|
@ -213,7 +215,7 @@ void CSpawnBotNpc::setFacing(CAngle theta)
|
|
|
|
|
{
|
|
|
|
|
_FacingTheta = pos().theta();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTheta(theta);
|
|
|
|
|
_FacingTick = CTimeInterface::gameCycle();
|
|
|
|
|
}
|
|
|
|
@ -260,8 +262,8 @@ std::vector<std::string> CSpawnBotNpc::getMultiLineInfoString() const
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> container;
|
|
|
|
|
std::vector<std::string> strings;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pushTitle(container, "CSpawnBotNpc");
|
|
|
|
|
strings.clear();
|
|
|
|
|
strings = CSpawnBot::getMultiLineInfoString();
|
|
|
|
@ -287,8 +289,8 @@ std::vector<std::string> CSpawnBotNpc::getMultiLineInfoString() const
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pushFooter(container);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return container;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -301,7 +303,7 @@ void CSpawnBotNpc::beginBotChat(CBotPlayer* plr)
|
|
|
|
|
nlwarning("Chat pair added more than once!!!");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add an entry to the bot chat vector
|
|
|
|
|
_ActiveChats.push_back(plr);
|
|
|
|
|
}
|
|
|
|
@ -313,11 +315,11 @@ void CSpawnBotNpc::endBotChat(CBotPlayer* plr)
|
|
|
|
|
{
|
|
|
|
|
if (_ActiveChats[i]!=plr)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// we've found a match for the player so remove the entry from the _aciveChats vector and return
|
|
|
|
|
_ActiveChats[i] = _ActiveChats[_ActiveChats.size()-1];
|
|
|
|
|
_ActiveChats.pop_back();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef NL_DEBUG
|
|
|
|
|
for (size_t j=i;j<_ActiveChats.size();++j)
|
|
|
|
|
{
|
|
|
|
@ -342,14 +344,14 @@ void CSpawnBotNpc::propagateAggro() const
|
|
|
|
|
CDynGrpBase* myDgb = pGroup->getGrpDynBase();
|
|
|
|
|
nlassert(myDgb);
|
|
|
|
|
CFamilyBehavior* myfb = myDgb->getFamilyBehavior();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CAIVision<CPersistentOfPhysical> vision;
|
|
|
|
|
// look for bots around
|
|
|
|
|
vision.updateBotsAndPlayers(pGroup->getAIInstance(), CAIVector(pos()), 0, (uint32)getAggroPropagationRadius());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef map<CSpawnBot*, float> TCandidatesCont;
|
|
|
|
|
TCandidatesCont candidates;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (myfb!=NULL)
|
|
|
|
|
{
|
|
|
|
|
FOREACH(it, CAIVision<CPersistentOfPhysical>, vision)
|
|
|
|
@ -358,32 +360,32 @@ void CSpawnBotNpc::propagateAggro() const
|
|
|
|
|
CSpawnBot* otherSpBot = otherPBot.getSpawnObj();
|
|
|
|
|
CGroup* otherPGroup = otherPBot.getOwner();
|
|
|
|
|
CSpawnGroup* otherSpGroup = otherPGroup->getSpawnObj();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If bot is in our group skip it
|
|
|
|
|
if (otherSpGroup==spGroup)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If bot is not in a dynamic system skip it
|
|
|
|
|
CDynGrpBase* otherDGB = otherPGroup->getGrpDynBase();
|
|
|
|
|
if (!otherDGB)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If bot is not in our family skip it
|
|
|
|
|
CFamilyBehavior* otherFB = otherDGB->getFamilyBehavior();
|
|
|
|
|
if (otherFB!=myfb)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ok, this group should help us !
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO : take only groups with the 'activity_figth' property
|
|
|
|
|
// filter out if the group is already in combat mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If group is not spawned skip it (???) (:TODO: See why this test)
|
|
|
|
|
if (!otherPGroup->isSpawned())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CProfilePtr& otherFightProfile = otherSpGroup->fightProfile();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!otherFightProfile.getAIProfile() || otherFightProfile.getAIProfileType()!=AITYPES::FIGHT_NORMAL || !(static_cast<CGrpProfileFight*>(otherFightProfile.getAIProfile())->stillHaveEnnemy()))
|
|
|
|
|
{
|
|
|
|
|
float dist = (float)CAIVector(otherSpBot->pos()).quickDistTo(pos());
|
|
|
|
@ -392,10 +394,10 @@ void CSpawnBotNpc::propagateAggro() const
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!candidates.empty())
|
|
|
|
|
nldebug("Tick %u, prop aggro from %p to %u bots", CTickEventHandler::getGameCycle(), this, candidates.size());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FOREACH (it, TCandidatesCont, candidates)
|
|
|
|
|
{
|
|
|
|
|
float propFactor = 1.0f - (it->second / getAggroPropagationRadius());
|
|
|
|
@ -435,7 +437,7 @@ void CSpawnBotNpc::setCurrentChatProfile(CNpcChatProfileImp* chatProfile)
|
|
|
|
|
{
|
|
|
|
|
if (chatProfile)
|
|
|
|
|
_CurrentChatProfile = *chatProfile;
|
|
|
|
|
else
|
|
|
|
|
else
|
|
|
|
|
_CurrentChatProfile.clear(); // clear the chat profile
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -466,7 +468,7 @@ CBotNpc::CBotNpc(CGroup* owner, uint32 alias, std::string const& name)
|
|
|
|
|
init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotNpc::~CBotNpc()
|
|
|
|
|
CBotNpc::~CBotNpc()
|
|
|
|
|
{
|
|
|
|
|
if (isSpawned())
|
|
|
|
|
{
|
|
|
|
@ -479,12 +481,12 @@ void CBotNpc::calcSpawnPos(RYAI_MAP_CRUNCH::CWorldMap const& worldMap)
|
|
|
|
|
CAIStatePositional const* const state = static_cast<CAIStatePositional*>(grp().getStartState());
|
|
|
|
|
RYAI_MAP_CRUNCH::CWorldPosition wp;
|
|
|
|
|
uint32 maxTries = 100;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
breakable
|
|
|
|
|
{
|
|
|
|
|
if (!state)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (state->shape().hasPatat() && state->shape().getRandomPosCount())
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
@ -497,11 +499,11 @@ void CBotNpc::calcSpawnPos(RYAI_MAP_CRUNCH::CWorldMap const& worldMap)
|
|
|
|
|
_StartPos.setTheta(0); // to initialise among vertices deltas (no?).
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!state->shape().hasPoints())
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
std::vector<CShape::TPosition> const& posList = state->shape().getGeometry();
|
|
|
|
|
|
|
|
|
|
std::vector<CShape::TPosition> const& posList = state->shape().getGeometry();
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
const uint32 a=CAIS::rand16((uint32)posList.size());
|
|
|
|
@ -560,15 +562,15 @@ std::string CBotNpc::getCustomLootTableId()
|
|
|
|
|
return _CustomLootTableId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CBotNpc::setPrimAlias(uint32 alias)
|
|
|
|
|
{
|
|
|
|
|
void CBotNpc::setPrimAlias(uint32 alias)
|
|
|
|
|
{
|
|
|
|
|
_PrimAlias = alias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32 CBotNpc::getPrimAlias() const
|
|
|
|
|
{
|
|
|
|
|
return _PrimAlias;
|
|
|
|
|
uint32 CBotNpc::getPrimAlias() const
|
|
|
|
|
{
|
|
|
|
|
return _PrimAlias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -578,18 +580,18 @@ void CBotNpc::fillDescriptionMsg(RYMSG::TGenNpcDescMsg& msg) const
|
|
|
|
|
msg.setBotAttackable(grp().getBotAttackable());
|
|
|
|
|
msg.setAlias(getAlias());
|
|
|
|
|
msg.setGrpAlias(grp().getAlias());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg.setSheet(getSheet()->SheetId());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg.setRightHandItem(getSheet()->RightItem());
|
|
|
|
|
msg.setRightHandItemQuality(1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg.setLeftHandItem(getSheet()->LeftItem());
|
|
|
|
|
msg.setLeftHandItemQuality(1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg.setDontFollow(isStuck());
|
|
|
|
|
msg.setBuildingBot(isBuildingBot());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i=0; i<_LootList.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
NLMISC::CSheetId const& sheetRef = _LootList[i];
|
|
|
|
@ -629,12 +631,12 @@ bool CBotNpc::finalizeSpawnNpc()
|
|
|
|
|
getSpawn()->setOutpostAlias(ownerOutpost->getAlias());
|
|
|
|
|
getSpawn()->setOutpostSide(_OutpostSide);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CMirrors::initSheetServer(getSpawn()->dataSetRow(), getSheet()->SheetId());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getSpawn()->setCurrentChatProfile(_ChatProfile);
|
|
|
|
|
getSpawn()->sendInfoToEGS();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_useVisualProperties) // use VisualPropertyA, B, C
|
|
|
|
|
{
|
|
|
|
|
sendVisualProperties();
|
|
|
|
@ -643,9 +645,9 @@ bool CBotNpc::finalizeSpawnNpc()
|
|
|
|
|
{
|
|
|
|
|
sendVPA ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getSpawn()->spawnGrp().botHaveSpawn(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -671,10 +673,10 @@ bool CBotNpc::spawn()
|
|
|
|
|
nlwarning("spawn() Aborted for bot '%s' due to bad sheet", getFullName().c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!CBot::spawn())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// :KLUDGE: Last part calls a tricky method also called by sheetChanged
|
|
|
|
|
// :TODO: Clean that mess
|
|
|
|
|
return finalizeSpawnNpc();
|
|
|
|
@ -688,12 +690,12 @@ void CBotNpc::sendVPA() // alternate VPA
|
|
|
|
|
CVisualSlotManager* visualSlotManager = CVisualSlotManager::getInstance();
|
|
|
|
|
NLMISC::CSheetId rightSheet = getSheet()->RightItem();
|
|
|
|
|
NLMISC::CSheetId leftSheet = getSheet()->LeftItem();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
visProp.Element.WeaponRightHand = visualSlotManager->rightItem2Index(rightSheet);
|
|
|
|
|
visProp.Element.WeaponLeftHand = visualSlotManager->leftItem2Index(leftSheet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setting up the visual property A mirror record
|
|
|
|
|
|
|
|
|
|
// setting up the visual property A mirror record
|
|
|
|
|
visProp.Element.ColorTop = getSheet()->ColorBody();
|
|
|
|
|
visProp.Element.ColorBot = getSheet()->ColorLegs();
|
|
|
|
|
visProp.Element.ColorHair = getSheet()->ColorHead();
|
|
|
|
@ -714,7 +716,7 @@ void CBotNpc::sendVPA() // alternate VPA
|
|
|
|
|
visProp.Element.ColorBoot,
|
|
|
|
|
visProp.Element.ColorArm,
|
|
|
|
|
visProp.Element.Seed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CMirrors::setVPA(getSpawn()->dataSetRow(), visProp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -732,7 +734,7 @@ bool CBotNpc::reSpawn(bool sendMessage)
|
|
|
|
|
{
|
|
|
|
|
if (!spawn())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getSpawn()->updateChat(grp().getCAIState());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@ -746,7 +748,7 @@ void CBotNpc::despawnBot()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CBotNpc::equipmentInit()
|
|
|
|
|
void CBotNpc::equipmentInit()
|
|
|
|
|
{
|
|
|
|
|
_Sheet->reset();
|
|
|
|
|
_Hat = false;
|
|
|
|
@ -762,7 +764,7 @@ void CBotNpc::equipmentAdd(std::string const& input)
|
|
|
|
|
// if string is empty just return without making a fuss
|
|
|
|
|
if (input.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// split string into keyword and tail
|
|
|
|
|
std::string keyword, tail;
|
|
|
|
|
if (!AI_SHARE::stringToKeywordAndTail(input,keyword,tail))
|
|
|
|
@ -773,7 +775,7 @@ void CBotNpc::equipmentAdd(std::string const& input)
|
|
|
|
|
input.c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do something depending on keyword
|
|
|
|
|
if (NLMISC::nlstricmp(keyword,"ri")==0)
|
|
|
|
|
{
|
|
|
|
@ -836,7 +838,7 @@ void CBotNpc::equipmentAdd(std::string const& input)
|
|
|
|
|
else if ( NLMISC::nlstricmp(keyword,"CLIENT_SHEET")==0 )
|
|
|
|
|
{
|
|
|
|
|
setClientSheet(tail + ".creature");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (NLMISC::nlstricmp(keyword,"loot")==0)
|
|
|
|
|
{
|
|
|
|
|
if (tail.empty())
|
|
|
|
@ -854,14 +856,14 @@ void CBotNpc::equipmentAdd(std::string const& input)
|
|
|
|
|
}
|
|
|
|
|
else if (NLMISC::nlstricmp(keyword, "USER_MODEL") == 0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32 primAlias = getAlias() >> LigoConfig.getDynamicAliasSize();
|
|
|
|
|
nldebug("Parsing userModelId '%s' with primAlias: '%u'", tail.c_str(), primAlias);
|
|
|
|
|
setPrimAlias(primAlias);
|
|
|
|
|
setUserModelId(tail);
|
|
|
|
|
}
|
|
|
|
|
else if (NLMISC::nlstricmp(keyword, "CUSTOM_LOOT_TABLE") == 0)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
uint32 primAlias = getAlias() >> LigoConfig.getDynamicAliasSize();
|
|
|
|
|
nldebug("Parsing customLootTableId '%s' with primAlias: '%u'", tail.c_str(), primAlias);
|
|
|
|
|
setPrimAlias(primAlias);
|
|
|
|
@ -878,14 +880,14 @@ void CBotNpc::equipmentAdd(std::string const& input)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Colors are something like that:
|
|
|
|
|
3D INTERFACE MP
|
|
|
|
|
0: ROUGE ROUGE RED
|
|
|
|
|
1: BEIGE ORANGE BEIGE
|
|
|
|
|
2: VERT CITRON VERT CITRON GREEN
|
|
|
|
|
3: VERT VERT TURQUOISE
|
|
|
|
|
4: BLEU BLEU BLUE
|
|
|
|
|
5: ROUGE dark ROUGE (normal) CRIMSON
|
|
|
|
|
6: BLANC JAUNE WHITE
|
|
|
|
|
3D INTERFACE MP
|
|
|
|
|
0: ROUGE ROUGE RED
|
|
|
|
|
1: BEIGE ORANGE BEIGE
|
|
|
|
|
2: VERT CITRON VERT CITRON GREEN
|
|
|
|
|
3: VERT VERT TURQUOISE
|
|
|
|
|
4: BLEU BLEU BLUE
|
|
|
|
|
5: ROUGE dark ROUGE (normal) CRIMSON
|
|
|
|
|
6: BLANC JAUNE WHITE
|
|
|
|
|
7: NOIR BLEU very dark BLACK
|
|
|
|
|
|
|
|
|
|
3D column is (probably) used for equipment
|
|
|
|
@ -894,7 +896,7 @@ void CBotNpc::setColour(uint8 colour)
|
|
|
|
|
{
|
|
|
|
|
_Sheet->setColorHead(colour);
|
|
|
|
|
_Sheet->setColorArms(colour);
|
|
|
|
|
_Sheet->setColorHands(colour);
|
|
|
|
|
_Sheet->setColorHands(colour);
|
|
|
|
|
_Sheet->setColorBody(colour);
|
|
|
|
|
_Sheet->setColorLegs(colour);
|
|
|
|
|
_Sheet->setColorFeets(colour);
|
|
|
|
@ -906,11 +908,11 @@ void CBotNpc::setColours(std::string input)
|
|
|
|
|
int const numColours = 8;
|
|
|
|
|
static std::vector <std::string> colourNames[numColours];
|
|
|
|
|
static bool init = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if string is empty just return without making a fuss
|
|
|
|
|
if (input.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!init)
|
|
|
|
|
{
|
|
|
|
|
// lookup 'ColourNames' in config file (should be a multi-line field)
|
|
|
|
@ -920,7 +922,7 @@ void CBotNpc::setColours(std::string input)
|
|
|
|
|
// for each line in config file var try to add an alternative name for one of the colour slots
|
|
|
|
|
for (uint i=0; i<varPtr->size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
// split line into name and idx (line example: 'red: 5')
|
|
|
|
|
// split line into name and idx (line example: 'red: 5')
|
|
|
|
|
std::string name, idxStr;
|
|
|
|
|
if (AI_SHARE::stringToKeywordAndTail(varPtr->asString(i),name,idxStr))
|
|
|
|
|
{
|
|
|
|
@ -994,12 +996,12 @@ void CBotNpc::setColours(std::string input)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i==numColours)
|
|
|
|
|
nlwarning("Failed to identify colour: '%s' in line: '%s'",colour.c_str(),input.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// assuming that we found more than 0 results pick one at random
|
|
|
|
|
if (results.empty())
|
|
|
|
|
{
|
|
|
|
@ -1151,9 +1153,10 @@ void CBotNpc::init()
|
|
|
|
|
{
|
|
|
|
|
_ChatProfile = NULL;
|
|
|
|
|
_MaxHitRangeForPC = -1.0f;
|
|
|
|
|
_DispersionRadius = 0;
|
|
|
|
|
// _MissionIconFlags.IsMissionStepIconDisplayable = true;
|
|
|
|
|
// _MissionIconFlags.IsMissionGiverIconDisplayable = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
equipmentInit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1169,21 +1172,38 @@ CSpawnBotNpc const* CBotNpc::getSpawn() const
|
|
|
|
|
|
|
|
|
|
void CBotNpc::getSpawnPos(CAIVector& triedPos, RYAI_MAP_CRUNCH::CWorldPosition& pos, RYAI_MAP_CRUNCH::CWorldMap const& worldMap, CAngle& spawnTheta)
|
|
|
|
|
{
|
|
|
|
|
if (_StartPos.isNull())
|
|
|
|
|
if (_DispersionRadius > 0)
|
|
|
|
|
{
|
|
|
|
|
RYAI_MAP_CRUNCH::CWorldPosition wp;
|
|
|
|
|
CAIVector rpos = _FirstPosition;
|
|
|
|
|
uint32 maxTries = 100;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
rpos = _FirstPosition;
|
|
|
|
|
rpos += randomPos(_DispersionRadius);
|
|
|
|
|
--maxTries;
|
|
|
|
|
}
|
|
|
|
|
while (!worldMap.setWorldPosition(AITYPES::vp_auto, wp, rpos) && maxTries>0);
|
|
|
|
|
if (maxTries > 0 ) {
|
|
|
|
|
nlinfo("set pos %f,%f", rpos.x().asDouble(), rpos.x().asDouble());
|
|
|
|
|
_StartPos.setXY(rpos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (_StartPos.isNull())
|
|
|
|
|
calcSpawnPos(worldMap);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isStuck() || IsRingShard)
|
|
|
|
|
worldMap.setWorldPosition(_VerticalPos, pos, _StartPos);
|
|
|
|
|
else
|
|
|
|
|
CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos, worldMap, pos, _StartPos, 10, 200, CWorldContainer::CPosValidatorDefault());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef NL_DEBUG
|
|
|
|
|
if (!pos.isValid() && !isStuck())
|
|
|
|
|
{
|
|
|
|
|
nlwarning("Npc Spawn Pos Error %s", pos.toString().c_str());
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
spawnTheta = _StartPos.theta();
|
|
|
|
|
triedPos = _StartPos;
|
|
|
|
|
}
|
|
|
|
@ -1220,20 +1240,20 @@ void CBotNpc::sheetChanged()
|
|
|
|
|
CAngle spawnTheta = getSpawnObj()->theta();
|
|
|
|
|
float botMeterSize = getSheet()->Scale()*getSheet()->Radius();
|
|
|
|
|
// :TODO: Save profile info
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If stuck bot position may be outside collision and must be recomputed
|
|
|
|
|
if (isStuck() || IsRingShard)
|
|
|
|
|
getSpawnPos(lastTriedPos, botWPos, CWorldContainer::getWorldMap(), spawnTheta);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Delete old bot
|
|
|
|
|
CMirrors::removeEntity(getSpawnObj()->getEntityId());
|
|
|
|
|
setSpawn(NULL); // automatic smart pointer deletion
|
|
|
|
|
notifyBotDespawn();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Finalize spawn object creation
|
|
|
|
|
if (!finalizeSpawn(botWPos, spawnTheta, botMeterSize))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// :KLUDGE: Both finalizeSpawn and finalizeSpawnNpc are called,
|
|
|
|
|
// sheetChanged has a strange herited meaning and may confuse future
|
|
|
|
|
// coders
|
|
|
|
@ -1252,16 +1272,16 @@ NLMISC_COMMAND(verboseNPCBotProfiles, "Turn on or off or check the state of verb
|
|
|
|
|
{
|
|
|
|
|
if (args.size()>1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (args.size()==1)
|
|
|
|
|
NLMISC::fromString(args[0], VerboseLog);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nlinfo("VerboseLogging is %s",VerboseLog?"ON":"OFF");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// virtual function so do not need to be inlined
|
|
|
|
|
bool CBotNpc::getFaunaBotUseBotName() const
|
|
|
|
|
{
|
|
|
|
|
return _FaunaBotUseBotName;
|
|
|
|
|
{
|
|
|
|
|
return _FaunaBotUseBotName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|